详细思路:http://blog.csdn.net/yutianzuijin/article/details/11954939/
或 https://blog.csdn.net/v_july_v/article/details/7041827
这两位聚聚的博客已经把KMP写得很详尽了,这里不再重复,把我自己遇到的问题写一下。
计算 next 数组的时候,如果位置 i 和位置 next[i] 的字符不相同,就要比较位置 i 和位置 next[next[i]] 的字符?
首先,在比较位置 i 的时候,前面已经有长度 next[i] 的前缀字符串S1和后缀字符串S2了,并且 S1==S2,那么 S1 中长度为 next[next[i]] 的前缀 t1 和 S2 中长度为 next[next[i]] 的后缀 t2 是相同的,那么再比较 t1 后面的一个字符和 t2 后面的一个字符就可以了,相等的话长度为 t1 的长度加1,否则继续找 t1 的前缀和 t2 的后缀。
#include<iostream>
#include<cstring>
using namespace std;
char T[10000]; //文本串
char P[200]; //要在文本串中找的字符串
int f[210]; //那位聚聚所说的next数组,这里用 f 数组代替
void getFail(char *P, int *f) //计算f数组
{
int m = strlen(P);
f[0] = f[1] = 0;
for (int i=1; i<m; i++)
{
int j = f[i];
while (j && P[i] != P[j]) j = f[j];
f[i+1] = P[i] == P[j] ? j+1 : 0;
}
}
int Find(char *T, char *P, int *f) //查找 P 是否在 T 中出现过,是则返回第一次出现的位置,否则返回-1
{
int n = strlen(T), m = strlen(P);
getFail(P, f);
int j = 0;
for (int i=0; i<n; i++)
{
while (j && T[i] != P[j]) j = f[j];
if (T[i] == P[j]) j++;
if (j == m)
return i-m+1; //找到字符串,返回字符串的起始位置
}
return -1; //没有找到,返回-1
}
int main()
{
cin>>T;
cin>>P;
cout<<Find(T, P, f)<<endl;
return 0;
}