http://blog.csdn.net/v_JULY_v/article/details/6111565 参考和july的编程之法
问题描述:有一个文本串S和一个模式串P,要查找P在S的位置该怎么做?(S[]="ABCDABABCDABD" P[]="ABCDABD")
分析:有暴力的方式可以解决,我们这里讨论一种经典的模式串匹配算法KMP,其核心是讨论如何产生Next[]数组,现对Next[]数组所表示的含义进行说明Next[ i ]表示当模式串第i的字符与文本串匹配出现失配的状况时,要用匹配串的那个下表来和S匹配。因为P和S已经匹配了一部分,我们已知已匹配的部分的文本串所以可以做一部分优化少比较几次。
Next[]的更直观的来说是当前P[i]字符以前,最长的前缀和后缀是多少
例如: 模式串P) A B C D A B D
相同前缀后缀) -1 0 0 0 0 1 2
P与S匹配 ABCDABABCDABD
ABCDABD 此时A与D不在匹配,这里不是通过暴力的方式重排,而是考虑到D之前的字符串的最大前缀后缀(2)这时只需将P向右移动Len(P) - Next[6]=4个位置 达到这种状态 ABCDABD 相信此时我们都看到了最大前缀和后缀的作用了,对Next[]的作用都有了一定的了解。
如何求Next[]:
Next[0] = -1 是一个标志的作用,连第一个P都没有匹配,文本串可以向右移一位了。
假设Next[1 - 4]都已经求出来了,此时求解Next[5],当然是if( P[5-1] == P[ next[5 - 1] ]) P[5] = Next[5 - 1 ] + 1
void Next(char *a,int *N)
{
N[0] = -1;
int k = -1;
int i = 1;
int len = strlen(a);
while(i <= len)
{
if( k == -1 || a[i-1] == a[k])
{
k ++;
if(a[i] != a[k])
{
N[i] = k;
}
else
{
N[i] = N[k];//此处考虑到了如果当前位置的a[i] == a[k] 虽然可以按原来的步骤求解next,但是a[i]失配,a[k]也是会失配的,此时考虑
} // 以k为失配符时情况相同,可以在纸上画一下,就可以理解了。
i ++;
}
else
k = N[k];
}
}
如何使用Next[]:
while(i < LenP && j < LenS)
{
if(S[j] == P[i]|| i == -1)//考虑最初的情况
{
j ++;
i ++;
}
else
{
i = N[i];
}
}
推荐例题:
hihocoder的题目 题目相信都能看懂,可是我咋提交的时候一直在TLE,一直超时,想了很多,最后发现暴力的主串一步一步向后移动并不能通过时间限制。我想到其实这里
还要考虑一下既然主串都已匹配过得,一定有方式可以优化这种判断,不要一步一步的移动,此时考虑模式串最后再添加一个字符*(匹配串中不存在的*),这样模式串永远都不会匹配成功,但是每当要匹配这个位置时,就已经把次数加一了。给出源码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
char A[10009],B[1000009];
int N[10009];
void Next(char *a)
{
N[0] = -1;
int k = -1;
int i = 1;
int len = strlen(a);
while(i <= len)
{
if( k == -1 || a[i-1] == a[k])
{
k ++;
if(a[i] != a[k])
{
N[i] = k;
}
else
{
N[i] = N[k];
}
i ++;
}
else
k = N[k];
}
}
int main()
{
int n,j;
int coun;
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
{
cin >> A;
cin >> B;
int Lena = strlen(A);
int Lenb = strlen(B);
int ab = 0;
coun = 0;
Next(A);
for(j = 0;j < Lenb;)
{
while(ab < Lena && j < Lenb)
{
if(B[j] == A[ab]|| ab == -1)
{
j ++;
ab ++;
}
else
{
ab = N[ab];
}
}
if(ab >= Lena)
{
ab = N[Lena];
coun++;
}
}
cout << coun << endl;
}
return 0;
}
希望可以帮到你理解KMP。理科生写的东西太少了,语言都不怎会组织,我把认为理解起来有点问题的都给了自己的看法。