KMP字符串匹配中next数组求法
char* strstr(char*str,char*pattern);//字符串很小O(m.n)
子串里面一头一尾有可以匹配上的小串,指针不用每次都回溯到最最开头的位置。
匹配前,对模式串进行详细分析, 搞清楚next值的含义,
p[0 ~ j]==p[ (i-j) ~i] ,即从p[0]开始长度为len=j+1,都有p[j]=
p[i] 那么一旦p[i+1]与t[?]不相等了,t[?]下一个就要与p[j+1]比较,next[i+1]=j+1
例如next[6]=3 ,模式串从0-5这个子串中,首尾能匹配的
小串从0开始这个小串尾部的下标 再往后挪一位
其实我们也可以发现, KMPKMP 算法之所以快,不仅仅由于它的失配处理方案,更重要的是利用前缀后缀的特性,从不会反反复复地找,我们可以看到代码里对于匹配只有一重循环,也就是说 KMPKMP 算法具有一种“最优历史处理”的性质,而这种性质也是基于 KMP 的核心思想的。
t[?]与p[0]都匹配失败了,
-1代表主串里面这个点不可能成功了,主串往后挪一个位置
把模式串最前面对着失败的位置 继续匹配
如果是与 p [ x ] ( x ! = 0 ) p [x](x!=0) p[x](x!=0)比较失败了,那么t[?]与next[x]匹配
这种形式可以成功获得匹配的位置,但是有一个缺陷,next数组的不能正确反映 模式串中首尾匹配的小串的真正长度
没有缺陷,根据观察比对,发现next【i】
i
∈
(
0
—
—
p
.
s
i
z
e
(
)
−
1
)
i∈( 0——p.size()-1 )
i∈(0——p.size()−1)表示了模式串前i个字符,即0~ i-1的这一段首尾匹配小串的长度,可是0~p.size()-1整个模式串这一段的首尾匹配小串长度却不可知。观察getNext()函数里对next数组的求值就可以发现,next数组的长度是
p
.
s
i
z
e
(
)
+
1
p.size()+1
p.size()+1而不是
p
.
s
i
z
e
(
)
p.size()
p.size(),也就是存在
n
e
x
t
[
p
.
s
i
z
e
(
)
]
next[p.size()]
next[p.size()], 可以表示0~p.size()-1整个模式串首尾匹配小串长度。
【模板】KMP字符串匹配
【模板】KMP字符串匹配
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e6+5;
int next[N];
void getNext(string p){
next[0]=-1;
int i=0;
int j=-1;
//在模式匹配串中首尾匹配的小串中,i指向尾小串最后一个字符
// j指向首小串最后一个字符,
// 也就是p[i+1]匹配不上时指针回溯的位置 j+1就要靠j定位
int len=p.size();//strlen
while(i<len){
if(j==-1||p[i]==p[j]){
i++;j++;//首尾小串依旧匹配就继续向前
next[i]=j;//相当于是p[i]=p[j]则next[i+1]=j+1
//至于j==-1,就是指针回溯到从-1开始比较,p[i+1]肯定就是从j==0开始比较
}
else{
j=next[j];//如果p[i]!=p[j],那么 p[i]就和next[j]比较
}
}
}
void kmp(string t,string p){
int lt=t.size();
int lp=p.size();
int i=0;
int j=0;
while(i<lt&&j<lp){
if(j==-1||t[i]==p[j]){
i++;
j++;
}
else j=next[j];//这样j就可能为-1,继而想到if中要判断j==-1
//j==-1模式串从0开始即j++,t[i]正是不能与p[0]匹配
if(j==(lp)){
cout<<i-lp+1<<endl;
j=next[j];//回溯到p【0】
}
}
}
int main(){
string t;
string p;
cin>>t>>p;
getNext(p);
kmp(t,p);
for(int i=1;i<=p.size();i++){
//next数组长度有p.size()+1,
// 后p.size()个值才是模式串里首尾匹配小串的长度
cout<<next[i]<<" ";
}
return 0;
}
还有种写法,避免next值取-1的
#include<iostream>
#include<cstring>
#define MAXN 1000010
using namespace std;
int next[MAXN];
int la,lb,j;
char a[MAXN],b[MAXN];
int main()
{
cin>>a+1;
cin>>b+1;
la=strlen(a+1);
lb=strlen(b+1);
for (int i=2;i<=lb;i++)
{
while(j&&b[i]!=b[j+1])
j=next[j];
if(b[j+1]==b[i])j++;
next[i]=j;
}
j=0;
for(int i=1;i<=la;i++)
{
while(j>0&&b[j+1]!=a[i])
j=next[j];
if (b[j+1]==a[i])
j++;
if (j==lb) {cout<<i-lb+1<<endl;j=next[j];}
}
for (int i=1;i<=lb;i++)
cout<<next[i]<<" ";
return 0;
}