在学习数据结构的过程中刚刚接触到kmp算法的时候不求甚解。但在写题的时候遇到了苦难,于是课后在百度上看了不少解释,但却感觉有些混乱,如有些下标从零开始,与教科书中有所不同。虽然它们本质上并没有什么区别,但我还是花了一些时间进行理解和消化。
一.next数组的求法
1.根据前面的字符的next值求
下标从1开始也就是教科书上的写法
将next【1】=0;next【2】=1;j=1;
从第 3 个开始,计算第 i 个位置的 next 值时,检查s.a【i】== s.a【j】?
相等,则 next【i】 = next【i-1】 + 1。
不等,则令j= next【i-1】,重复上面的操作直到下标为1还不等,则赋next【i】为1。
下面是具体的代码
void get_next(int next[],S s)
{
int i=1,j=0;
next[1]=0;
while(i<s.length)
{
if(j==0||s.a[j]==s.a[j])
{
++i;
++j;
next[i]=j;
}
else
j=next[j];
}
}
2.根据最大公共元素长度求
模式串 | a | b | c | a | a | b | b | a | b | c | a | b |
---|---|---|---|---|---|---|---|---|---|---|---|---|
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
next | 0 | 0 | 0 | 1 | 0 | 2 | 0 | 1 | 2 | 3 | 4 | 2 |
如上图所示,下表从零开始,令next【0】=0,前i个字符的最长的相同前后缀即为当前next【i】的值
例如 abcaabbabca的最长的相同前后缀为abca,所以next【10】=4
代码如下:
void get_next(int next[],S s)
{
next[0]=0;
for(int i=1,j=0; i<s.length; i++)
{
while(j!=0&&s.a[j]!=s.a[i])
j=next[j-1];
if(s.a[j]==s.a[i])
j++;
next[i]=j;
}
}
kmp的应用
题: 医学研究者最近发现了某些新病毒,通过对这些病毒的分析,得知他们的DNA序列都是环状的。现在研究者已收集了大量的病毒DNA和人的DNA数据,想快速检测出这些人是否感染了相应的病毒。为了方便研究,研究者将人的DNA和病毒DNA均表示成由一些字母组成的字符串序列,然后检测某种病毒DNA序列是否在患者的DNA序列中出现过,如果出现过,这此人感染了该病毒,否则没有感染。例如,假设病毒的DNA序列为baa,患者1的DNA序列为aaabbba,则感染。患者2的DNA序列为babbba,则未感染。(注意:人的DNA序列是线性的,而病毒的DNA序列是环状的)。
#include<bits/stdc++.h>
#define maxsize 100000
using namespace std;
int next[maxsize];
typedef struct
{
char a[maxsize];
int length;
} S;
void bt(S &s)
{
cin>>s.a;
s.length=strlen(s.a);
}
void get_next(int next[],S s)
{
next[0]=0;
for(int i=1,j=0; i<s.length; i++)
{
while(j!=0&&s.a[j]!=s.a[i])
j=next[j-1];
if(s.a[j]==s.a[i])
j++;
next[i]=j;
}
}
int kmp(S s1,S s2)
{
int i=0,j=0;
while(i<s2.length&&j<s1.length)
{
if(j==0&&s2.a[i]!=s1.a[j])
{
i++;
continue;
}
if(s2.a[i]==s1.a[j])
{
i++;
j++;
}
else
j=next[j];
}
if(j>=s1.length)
return 1;
else
return 0;
}
int main()
{
do
{
int n;
S s1,s2;
bt(s1);
bt(s2);
if(strcmp(s1.a,"0"))
;
else if(strcmp(s2.a,"0"));
else
break;
char ss[maxsize*2],s[maxsize];
strcpy(ss,s1.a);
strcat(ss,s1.a);
for(n=0; n<s1.length; n++)
{
int next[maxsize];
for(int m=0; m<s1.length; m++)
s[m]=ss[n+m];
strcpy(s1.a,s);
get_next(next,s1);
if(kmp(s1,s2))
{
cout<<"YES"<<endl;
break;
}
}
if(n==s1.length&&(!kmp(s1,s2)))
cout<<"NO"<<endl;
}
while(1);
}
结果: