之前比赛的时候,一道KMP的题目没有做出来,很是郁闷。最近一两天仔细研究了一下KMP,收获不少。
基本的KMP思想算法什么的就不再赘述了。只是我在网上找资料的时候发现KMP的失配数组(next[])有两个版本,但是几乎没有资料将这两个版本的next[]做一个较好的分析。于是,写了这篇blog,对这两类next[]做了一个简单的分析,希望对大家有帮助,也希望大家能指出其中的错误和不足。由于直接贴文本格式难以控制,于是一部分内容被做成了图片。分析如下:
第一类next数组求解函数:
Code
1 void KMP_next(char b[], int pre[]) {
2 int n = (int)strlen(b), k;
3 pre[0] = -1; k = -1;
4 for(int i = 1; i < n; i++) { //没有i == n
5 while(k > -1 && b[k+1] != b[i]) k = pre[k];
6 if(b[k+1] == b[i]) k++;
7 pre[i] = k;
8 }
9 }
第二类next数组求解函数:
Code
1 void KMP_next(char s[], int pre[]) {
2 int i = 0, j = -1, n = (int)strlen(s);
3 pre[0] = -1;
4 while(i <= n) { //注意有i == n
5 if(j == -1 || s[j] == s[i]) {
6 i++; j++;
7 pre[i] = j;
8 }
9 else j = pre[j];
10 }
11 } POJ 3461 Oulipo这道题用两类KMP都可以过,但是代码上有一些细微的差别。本人比较喜欢第一类KMP,于是就贴第一类的代码了。
POJ 3461 Oulipo
1 #include <stdio.h>
2 #include <string.h>
3
4 const int MaxN = 1000010;
5
6 char word[MaxN/10], txt[MaxN];
7 int next[MaxN/10];
8
9 void KMP_next(char b[], int pre[]) {
10 int n = (int)strlen(b), k;
11 pre[0] = -1; k = -1;
12 for(int i = 1; i < n; i++) {
13 while(k > -1 && b[k+1] != b[i]) k = pre[k];
14 if(b[k+1] == b[i]) k++;
15 pre[i] = k;
16 }
17 }
18
19 int main() {
20 int n;
21 for(scanf("%d%*c", &n); n--;) {
22 gets(word); gets(txt);
23 KMP_next(word, next);
24 int cnt = 0, len = (int)strlen(word);
25 for(int i = 0, j = -1; txt[i]; ++i) {
26 while(j > -1 && word[j+1] != txt[i])
27 j = next[j];
28 if(word[j+1] == txt[i])
29 j++;
30 if(j == len-1) {
31 cnt++; j = next[j];
32 }
33 }
34 printf("%d\n", cnt);
35 }
36 return 0;
37 }