*算法介绍:
扩展KMP算法是对KMP算法的一种扩展,对于求两个字符串的公共部分非常有效。题目可以有多种变化。最普通的的是给定母串text与子串part。求数组extend[i],extend[i]表示text[i...n]字符串与part最长前缀的长度。
*思路:
1.主代码:
与KMP的思路一致,我们设next数组表示:next[i...n]与next数组本身的最长公共前缀长度。
假设我们现在已经知道extend[0....i]的值,接下来要求extend[i+1]的值。设1<=k<=i,且使k+extend[k]最大(这意味着以text[k]为前缀匹配时,在text字符串中匹配达到最远)。
据extend[k]得:
text[k...k+extend[k]-1]=part[0...extend[k]-1]
所以可以推知:
text[i...k+extend[k]-1]=part[i-k...extend[k]-1]
根据next数组的意义可以知道以part[i-k]为前缀与part数组的前缀匹配时,匹配长度L=next[i-k]。我们至少可以知道text[i...k+extend[k]-1]与part[0...next[i-k]-1]匹配,长度为L。
(1)若:L+i
(2)若:L+i>=k+extend[k] 我们目前只能确定(1)中的L个字符匹配,接下来不能确定,所以需要挨个比较,并且比较完后需令:k=i+1。
2.next数组的获取:
与KMP数组的next数组获取思路相同,将以上算法对part字符串自身使用,即可得到。思路分析时只需将上述思路分析中的text字符串替换为part字符串本身,将extend数组替换为next数组即可求得。
*代码:
#include<iostream> #include<cstring> using namespace std; int next[1000],lent,lenp,extend[1000]; char text[1000],part[1000]; void get_next() { int j=0,i=0,p,l,k; next[0]=lenp; while(j<lenp&&part[j]==part[j+1]) j++; next[1]=j; k=1; for(i=2;i<lenp;i++) { p=next[k]+k-1,l=next[i-k]; if(l+i-1<p) next[i]=l; else { j=max(0,p+1-i); while(i+j<lenp&&part[j]==part[i+j]) j++; next[i]=j; k=i; } } } int extend_KMP() { int i,j=0,l,k=0,p; get_next(); while(j<lent&&j<lenp&&part[j]==text[j]) j++; extend[0]=j; for(i=1;i<lent;i++) { l=next[i-k]; p=extend[k]+k-1; if(l+i-1<p) extend[i]=l; else { j=max(0,p+1-i); while(j+i<lent&&part[j]==text[i+j]) j++; extend[i]=j; k=i; } } } int main() { int i; cin>>part>>text; lenp=strlen(part); lent=strlen(text); extend_KMP(); for(i=0;i<lenp;i++) cout<<next[i]; cout<<endl; for(i=0;i<lent;i++) cout<<extend[i]; return 0; }