您的位置:首页 > 其它

大话kmp! (模版测试题hdu1171)

2016-03-15 21:45 302 查看
kmp是数据结构里面关于字符串很重要的内容

关于kmp,网上有很多资料,但是有的人看了看懂了,有的看了还是看不明白

所以我自己还是要自己整理一下。

关于kmp求next数组,这是最难的,很难理解,尤其是那一句k=next[k],真的是让人费解

首先,kmp高效的原因是因为,进行了预处理,然后匹配时主串不回溯,使得kmp效率达到了O(n+m),比起普通的暴力匹配高效了不少。

首先我们来分析一下get_next函数,这个是得到next数组的函数。

i的含义是求next[i+1]的值,j的含义是上一个next[]的值是多少,比如上一个j是5,然后这时t[i]==t[j],就是表示此时的next[i+1]==6,因为next数组表示的是最长前缀后缀

j==-1的时候,next[i]=0,这个不难理解。

t[i]==t[j]的时候,更好,直接+1了。

当t[i]==t[j]的时候,很有可能这个答案是0,也可能介于0~j-1之间了,反正不会超过j了,因为唯一一次等于j+1的机会已经错过了(t[i]==t[j]),于是我们该怎么选择,于是先辈们就说,选择k=next[k]这个位置!

为什么?

http://www.rudy-yuan.net/archives/182/

我也想讲,但是这篇博客讲的很清楚,我自己在记事本上的图画的太丑了,实在是不好看清楚,就直接看这篇博客把!

void get_Next(int m){
next_[0]=-1;
for(int i=0,j=-1;i<m;){
if(j==-1||t[i]==t[j]){
i++;j++;
next_[i]=j;
}
else j=next_[j];
}

/*
int j=0,k=-1;
while(j<m){
while(k>=0&&t[j]!=t[k]){
k=next_[k];
}
j++;k++;
next_[j]=k;
}
*/
}


这里的get_next函数还有下面注释部分的写法,其实都是一样的。

int kmp_solve(int n,int m){
get_Next(m);
int i=0,j=0;
while(i<n&&j<m){
if(s[i]==t[j]){
i++;j++;
}
else if(next_[j]==-1){
i++;
}
else j=next_[j];
}
if(j>=m)return i-j+1;
return -1;
}


可以看到

else if(next_[j]==-1)

这一句有人会发现和网上的代码不一样,当然在这里,很多人写的是j==0,这里写成这样我觉得更好理解。

其实都是一样的,根据我们求next的代码,计算next[i]时,j是++过的,这就意味着除了j==0之外,没有别的next值会是-1,但是我写成这样,可以理解为,我们下面要将next[j]得值赋值给j,所以我们排出j==-1的情况,以免运行错误。当然这只是一种理解,正确而且比较官方有信服力的解答是,这条语句,如果s[i]和t[0]不想等,那么i就可以直接++了,不用在调整j的位置了,因为对于i位置,t串已经不想等了,可以直接进行下一次匹配了。

写代码:(这个代码是hdu1171的代码,纯kmp模版)

#include<iostream>
using namespace std;
#include<cstring>
#include<cstdio>

const int maxn=1000005;
int s[maxn];
int t[maxn];
int next_[maxn];

void get_Next(int m){ next_[0]=-1; for(int i=0,j=-1;i<m;){ if(j==-1||t[i]==t[j]){ i++;j++; next_[i]=j; } else j=next_[j]; } /* int j=0,k=-1; while(j<m){ while(k>=0&&t[j]!=t[k]){ k=next_[k]; } j++;k++; next_[j]=k; } */ }

int kmp_solve(int n,int m){ get_Next(m); int i=0,j=0; while(i<n&&j<m){ if(s[i]==t[j]){ i++;j++; } else if(next_[j]==-1){ i++; } else j=next_[j]; } if(j>=m)return i-j+1; return -1; }
int main(){
int T;
cin>>T;
while(T--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%d",&s[i]);
}
for(int i=0;i<m;i++){
scanf("%d",&t[i]);
}
int ans;
if(n>=m)
ans=kmp_solve(n,m);
else ans=-1;
cout<<ans<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: