又到了一学期一次的考试周,然后同学说数据结构要考KMP,然后训练计划上正好也有KMP就顺便看了一下。
话说KMP这个算法还是挺形象的,整个算法建立在next数组之上。next[i]存储的为若在第 i 个字符处匹配失败,指针应回指到的位置。
关于KMP的讲解,数据结构课本上已经讲得很详细了,然后网上也有很多博客讲得很不错,所以在这里就不重复了。
下面推荐一下几篇不错的博客。
http://www.matrix67.com/blog/archives/115
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
http://blog.csdn.net/v_july_v/article/details/7041827
接下来自己对这几个题的思路。
POJ3461就不用多说了,KMP最基本的应用了。
POJ1961若有 s[i] == s[next[i]] && (i+1)%(i-next[i]) == 0 则说明找到一种符合题意的情况。
POJ 2406 / SDUT 2747 其实是一种题。一个是输出N,一个是输出符合要求的子串。
若 s[l-1] == s[next[l-1]] && l % (l-1-next[l-1]) == 0 输出 l / (l-1-next[l-1]);
否则其本身就是符合情况的最小的子串,输出 l 即可。
SDUT2747的数据较弱,暴力枚举也可以。
SDUT 2747
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #define LL long long int using namespace std; char s1[1000100]; int next[1000100]; int k[1000100]; int main() { int i,j,l; while(scanf("%s",s1) != EOF) { l = strlen(s1); i = 0,next[0] = -1,j = -1; while(i < l) { if(j == -1 || s1[i] == s1[j]) { ++i; ++j; next[i] = j; } else { j = next[j]; } } i = l-1; if(s1[i] == s1[next[i]] && (i+1)%(i-next[i]) == 0) { s1[i-next[i]] = '\0'; } printf("%s\n",s1); } return 0; }
POJ 1961
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #define LL long long int using namespace std; char s1[1000100]; int next[1000100]; int k[1000100]; int main() { int i,j,l; int icase = 0; while(scanf("%d",&l) && l) { scanf("%*c%s",s1); i = 0,next[0] = -1,j = -1; while(i < l) { if(j == -1 || s1[i] == s1[j]) { ++i; ++j; next[i] = j; } else { j = next[j]; } } printf("Test case #%d\n",++icase); for(i = 0; i < l; ++i) { if(next[i] == -1) { k[i] = 1; } else { if(s1[i] == s1[next[i]] && (i+1)%(i-next[i]) == 0) { k[i] = k[next[i]]+1; printf("%d %d\n",i+1,k[i]); } else { k[i] = 1; } } } printf("\n"); } return 0; }
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #define LL long long int using namespace std; char s1[1000100],s2[10100]; int next[1000100]; int main() { int T; int l1,l2,i1,i2,i,j,l,ans; scanf("%d",&T); while(T--) { scanf("%*c%s",s2); scanf("%*c%s",s1); l = strlen(s2); i = 0,next[0] = -1,j = -1; while(i < l) { if(j == -1 || s2[i] == s2[j]) { ++i; ++j; next[i] = j; } else { j = next[j]; } } l1 = strlen(s1); l2 = l; for(i1 = 0,i2 = 0,ans = 0;i1 < l1 ;) { //cout<<"i1 = "<<i1<<" i2 = "<<i2<<" s2[i2] = "<<s2[i2]<<" next[i2] = "<<next[i2]<<endl; if(i2 != l2 && (i2 == -1 || s1[i1] == s2[i2]) ) { i1++; i2++; } else i2 = next[i2]; if(i2 == l2) { ans++; } } printf("%d\n",ans); } return 0; }