KMP之next总结
2016-07-18 22:07
225 查看
KMP最难理解的就是next[],
next[]表示往回翻的位置,也等同于当前位置下(好理解,可以只理解这一种的代码写法)||当前位置的前一个下,前缀=后缀的最大个数。
其实next[]数组举好例子就很好理解:
首先定义一下:next的意思就是指大的字符串前缀==后缀,我们把该前缀或者后缀称之为小字符串,那么小字符串里还有前缀==后缀的串,我们称之为小小字符串,小小字符串中还有小小小字符串……那么当遇到字符串不匹配的情况下,我们要往前翻,翻到比自己小一号的字符串前缀末尾,去判断它的下一位是否等于a[i](后缀不匹配的字符)。
画图:
举个例子:
abcabdabcabc
分两种情况:
1.数组下标从1开始(容易理解的例子)
2.数组下标从零开始
解释一下例子:
字符数组中最后一个”c”字母如果是“d”,那么next[12]将会是6,但是前缀最后一个字符不等于后缀的字符,由字母”d”的前一位就要往回翻(为什么是前一位等同于为什么判断a[j+1]?=a[i]是一个道理,等会解释),也就是翻到下标为2的地方字母为“b”的地方,然后再次判断a[j+1]?=a[i],可以看出前后缀都是abc,那么next[12]=3;
next[]的含义就是在当前位置下,前缀==后缀的最大个数;另一个含义是往前翻到的地方正好是当前子字符串中前缀等于后缀的前缀末尾字符的下标。
解释为什么是a[j+1]?=而不是a[j]:
我们用j表示前缀,用i表示后缀指向,那么如果a[前缀]!=a[后缀],那么前缀就要往前翻,翻到的地方一定还是前缀==后缀处位置,再判断它的下一个位置字符是否相等(a[j+1]?=a[i]),因此判断的是j+1位置。
代码:
定义一个j记录前缀的下标,一个i记录后缀的下标。
另一个含义就是在当前位置的前一个位置下,前缀==后缀的最大个数。
代码大同小异,也是前缀末尾前一个字符往前翻,翻到子串相同位置:
next[]表示往回翻的位置,也等同于当前位置下(好理解,可以只理解这一种的代码写法)||当前位置的前一个下,前缀=后缀的最大个数。
其实next[]数组举好例子就很好理解:
首先定义一下:next的意思就是指大的字符串前缀==后缀,我们把该前缀或者后缀称之为小字符串,那么小字符串里还有前缀==后缀的串,我们称之为小小字符串,小小字符串中还有小小小字符串……那么当遇到字符串不匹配的情况下,我们要往前翻,翻到比自己小一号的字符串前缀末尾,去判断它的下一位是否等于a[i](后缀不匹配的字符)。
画图:
1 2 3 3 3 3 2 2 3 3 3 3 2 1 [ [ [ ]z [ ] ] x... [ [ ] [ ] ] ] y //1表示一个大的字符串,2表示小字符串:1的前缀==后缀,也就是2围城的括号内容相等, 3表示2的小字符串,里面内容相等,当1串中x!=y,也就是2+x!=2+y,那么我们将x的前 一个字符往回翻,得到第一个3串末尾字符,在判断第一个3串的下一个字符z是否等于y, 为什么可以这样判断呢,在于四个3串都相等,那么第一个3串==最后一个3串。 因此next一直在取前缀等于后缀的小串,直到取到一个小串的下一个字符等于大串尾字符。
举个例子:
abcabdabcabc
分两种情况:
1.数组下标从1开始(容易理解的例子)
2.数组下标从零开始
1.情况一
0,1,2,3,4,5,6,7,8,9,10,11,12 下标 a,b,c,a,b,d,a,b,c, a, b, c 字母 0,0,0,1,2,0,1,2,3, 4, 5, 3 next[]
解释一下例子:
字符数组中最后一个”c”字母如果是“d”,那么next[12]将会是6,但是前缀最后一个字符不等于后缀的字符,由字母”d”的前一位就要往回翻(为什么是前一位等同于为什么判断a[j+1]?=a[i]是一个道理,等会解释),也就是翻到下标为2的地方字母为“b”的地方,然后再次判断a[j+1]?=a[i],可以看出前后缀都是abc,那么next[12]=3;
next[]的含义就是在当前位置下,前缀==后缀的最大个数;另一个含义是往前翻到的地方正好是当前子字符串中前缀等于后缀的前缀末尾字符的下标。
解释为什么是a[j+1]?=而不是a[j]:
我们用j表示前缀,用i表示后缀指向,那么如果a[前缀]!=a[后缀],那么前缀就要往前翻,翻到的地方一定还是前缀==后缀处位置,再判断它的下一个位置字符是否相等(a[j+1]?=a[i]),因此判断的是j+1位置。
代码:
#include<cstdio> #include<cstring> char s[1005]; d765 int next[1005],n,j; int main() { scanf("%s",s+1); for(int i=2,j=0;i<=strlen(s+1);i++) { while(j>0 && s[j+1] != s[i]) j=next[j]; if(s[j+1]==s[i]) j++; next[i]=j; } for(int i=1;i<=strlen(s+1);i++) printf("%d ",next[i]); }
1.情况二
0,1,2,3,4,5,6,7,8,9, 10,11,12 下标 a,b,c,a,b,d,a,b,c, a, b, c 字母 -1,0,0,0,1,2,0,1,2, 3, 4, 5 next[]
定义一个j记录前缀的下标,一个i记录后缀的下标。
另一个含义就是在当前位置的前一个位置下,前缀==后缀的最大个数。
代码大同小异,也是前缀末尾前一个字符往前翻,翻到子串相同位置:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; char s[1001]; int next[1001]; int main() { scanf("%s",s); next[0]=-1; for(int i=1,j=-1;i<strlen(s);i++) { while(j>-1 && s[i]!=s[j+1]) j=next[j]; if(s[i]==s[j+1]) j++; next[i+1]=j+1; } for(int i=0;i<strlen(s);i++) cout<<next[i]<<" "; }
相关文章推荐
- android 布局滑动中scrollTo 和 scrollBy 方法使用说明
- 我的第一个小项目上线啦&sql注入式攻击
- HDU 5695 Gym Class(拓扑排序、优先队列)
- HDU 2087(KMP)
- html
- 字符串编辑距离(相似度)
- CCNA系列二之RIP路由
- 论菜鸟的自我修养
- [fjwc2015]Screen [从hzw神犇那里扒来的题]
- AJAX
- 网络游戏分类
- c++教程(二:Structure of a program)
- c++ 中 define
- Java之Socket上的Read操作阻塞问题
- 四种线程池的使用
- 7月第三周——任务
- km算法学习小记
- Apache:使用mod_wsgi时自动reload代码
- JavaWeb---制作验证码
- oracle_sql的用法?