扩展KMP

*算法介绍:

    扩展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;
}

 

posted @ 2013-09-05 20:47  Neptunes  阅读(268)  评论(0编辑  收藏  举报