next[i]表示去掉第i个元素后,自已的前缀和后缀完全匹配的最大长度

字符串    a b a b a b z a b a b a b a
next   -1 0 0 1 2 3 4 0 1 2 3 4 5 6 0 前缀和后缀是啥意思呢

abababz 前缀有 a ab aba abab ababa ababab 不算最后一个
      后缀有 z bz abz babz ababz bababz 不算第一个
void getNext()
{
int j, k;
j = ; k = -; next[] = -;
while(j < tlen)
if(k == - || T[j] == T[k])
next[++j] = ++k;
else
k = next[k]; }

根据代码一个个匹配就好了

关键在于next的回溯  为什么要这样回溯

我们再看 字符串  a b a b a b z a b a b a b a

每一个最长长度有两种来源  1、如果当前字符匹配 则由上一个最长长度加一    2、如果不匹配 则看次长长度的下一个字符是否与当前字符匹配。。不匹配就看次次长长度。。以此类推

为什么呢。。。因为我们想要得到到当前位置的最长匹配长度。。

那为什么k = next[k]就能到次长长度的下一个位置呢。。

我们就看上边那个个字符串  z的下标为6  next[6] = 4表示 去掉位置6的字符后所能匹配的最大长度

那么 这个长度4是由上一个位置推出来的

那么上一个位置是不是就是当前位置的次长长度

既然是上一个位置 为什么 不是k = j - 1而是k = next[k]呢

因为j代表后缀的位置 而k是前缀的位置  因为是找一个次大的前缀来匹配当前后缀

而next[k]是除去k之后的最大匹配长度 即下标k前的最大匹配长度(当然 一定到k-1)

其实意思很好懂。。。。记得平行吗。。a//b  b//c  a//c

那next[k]不就是能和j匹配的前缀的位置吗。。。

所以这个长度就是

匹配就和人情世故一样。。。能通融一下通融一下。。。大的不行那就次大。。次大不行。。。那就次次大。。嗯。。就是这样。。kmp就是遵循了这个法则。。是的。。

bin神kmp模板

/*
pku3461(Oulipo), hdu1711(Number Sequence)
这个模板 字符串是从0开始的
Next数组是从1开始的 */
#include <iostream>
#include <cstring>
using namespace std; const int N = ;
int next[N];
char S[N], T[N];
int slen, tlen; void getNext()
{
int j, k;
j = ; k = -; next[] = -;
while(j < tlen)
if(k == - || T[j] == T[k])
next[++j] = ++k;
else
k = next[k]; }
/*
返回模式串T在主串S中首次出现的位置
返回的位置是从0开始的。
*/
int KMP_Index()
{
int i = , j = ;
getNext(); while(i < slen && j < tlen)
{
if(j == - || S[i] == T[j])
{
i++; j++;
}
else
j = next[j];
}
if(j == tlen)
return i - tlen;
else
return -;
}
/*
返回模式串在主串S中出现的次数
*/
int KMP_Count()
{
int ans = ;
int i, j = ; if(slen == && tlen == )
{
if(S[] == T[])
return ;
else
return ;
}
getNext();
for(i = ; i < slen; i++)
{
while(j > && S[i] != T[j])
j = next[j];
if(S[i] == T[j])
j++;
if(j == tlen)
{
ans++;
j = next[j];
}
}
return ans;
}
int main()
{ int TT;
int i, cc;
cin>>TT;
while(TT--)
{
cin>>S>>T;
slen = strlen(S);
tlen = strlen(T);
cout<<"模式串T在主串S中首次出现的位置是: "<<KMP_Index()<<endl;
cout<<"模式串T在主串S中出现的次数为: "<<KMP_Count()<<endl;
}
return ;
}
/*
test case
aaaaaa a
abcd d
aabaa b
*/

最新文章

  1. linux下安装zookeeper(单机版)
  2. UML类图基本元素符号
  3. 将查询字符串解析转换为泛型List的名值集合.
  4. block做方法参数时--block的参数传值过程 例1
  5. Sqlserver 远程连接的 TCP/IP 和 Named Pipes的区别
  6. 13)Java static
  7. Python学习教程(learning Python)--3.2 if-else分支语句
  8. iOS Core Animation学习总结(3)--动画的基本类型
  9. 删除Windows右键不用的选项
  10. RHEL7单独安装图形X11
  11. tableView Crash
  12. HDU 4081 MST
  13. jquery Ztree v3.5 实例2 自定义显示在节点前的图片
  14. C++面试题一大波
  15. JAVA 保留两位小数的四种方法
  16. 把VBScript的函数迁移到C#.NET
  17. 二分(HDU2289 Cup)
  18. entrySet用法 以及遍历map的用法
  19. Python中的格式化输出
  20. java学习之路--继承(子类构造器)

热门文章

  1. 【转载】Ogre3d 2.1 源码编译安装教程
  2. 【LG4091】[HEOI2016/TJOI2016]求和
  3. clean code(一)
  4. 《Node.js核心技术教程》学习笔记
  5. 做程序开发的你如果经常用Redis,这些问题肯定会遇到
  6. 在Windows2008下添加iscsi存储出现磁盘Offine(The disk is offine because of policy set by an adminstrator)的解决方法
  7. 使用qemu启动dd制作的img镜像
  8. python单元测试之参数化
  9. “Hello World!”团队第七周召开的第一次会议
  10. Python:集合操作总结