扩展kmp

利用到了 k m p kmp kmp m a n a c h e r manacher manacher的部分思想。
个人理解只能称的上是部分。
扩展kmp处理的是:对于一个串 T T T,串 S S S每个后缀和串 T T T的最长公共前缀。

对于一个串 S [ 1...10 ] , T [ 1...100 ] S[1...10],T[1...100] S[1...10],T[1...100]
如果已经匹配到了 S [ 1...10 ] = T [ 1...10 ] S[1...10]=T[1...10] S[1...10]=T[1...10].
S [ 1...5 ] = S [ 2...6 ] S[1...5]=S[2...6] S[1...5]=S[2...6]
[以上为条件]
容易得到: S [ 2..6 ] = S [ 1...5 ] = T [ 1...10 ] S[2..6]=S[1...5]=T[1...10] S[2..6]=S[1...5]=T[1...10]。这正是利用到了 k m p kmp kmp的思想。我们得到了这部分处理过后的信息,然后继续处理。(暴力判断)
但是 k m p kmp kmp中预处理的 n e x t next next数组表示的意思是最长相同前缀后缀。而这里的 n e x t next next数组表示的是最长相同前缀[具体是串 S S S i i i个点开始的后缀和 S S S的最长公共前缀。]

显然这一部分信息等价于题目要求最长公共前缀。
那么怎么求解呢?

首先假设我们已经处理出了 1   k 1~k 1 k的情况,并且之前匹配过的最远位置是 p p p p = m a x ( i + e x t e n d [ i ] − 1 ) p=max(i+extend[i]-1) p=max(i+extend[i]1)设取最大值的位置是 p 0 p0 p0
这里是盗用了洛谷题解里的图片。
在这里插入图片描述
我们在处理 k + 1 k+1 k+1的时候, k + 1 + n e x t [ k + 1 ] − 1 &lt; k+1+next[k+1]-1&lt; k+1+next[k+1]1< &gt; = p &gt;=p >=p我们分两种情况.
首先设 L = n e x t [ k + 1 ] L=next[k+1] L=next[k+1]

  1. L + K &lt; P L+K&lt;P L+K<P
    S [ k + 1... k + L ] = T [ b . . . b + L − 1 ] 。 S[k+1...k+L]=T[b...b+L-1]。 S[k+1...k+L]=T[b...b+L1]这一部分由于在p以内,显然是匹配过的。
    T [ b . . . b + L − 1 ] = T [ 1... L ] = S [ k + 1... k + L ] 。 T[b...b+L-1]=T[1...L]=S[k+1...k+L]。 T[b...b+L1]=T[1...L]=S[k+1...k+L]
    同时 T [ b + L ] ! = T [ L + 1 ] , T[b+L]!=T[L+1], T[b+L]!=T[L+1]因为这是计算过的最大前缀,必然后面不相等.
    T [ 1 + L ] ! = T [ L + b ] = S [ k + L + 1 ] T[1+L]!=T[L+b]=S[k+L+1] T[1+L]!=T[L+b]=S[k+L+1]。因为 L + K &lt; P , L+K&lt;P, L+K<P这部分信息已经匹配过相等,但是又有前面不相等,所以。 T [ 1 + L ] ! = S [ k + L + 1 ] . T[1+L]!=S[k+L+1]. T[1+L]!=S[k+L+1].
    L L L S [ k + 1 ] S[k+1] S[k+1] T T T最大公共前缀。
  2. L+K≥P
    此时情况比较复杂。
    我们能够确定的是: S [ k + 1... P ] = T [ b . . . P − P 0 + 1 ] = T [ 1.. p − k ] S[k+1...P]=T[b...P-P0+1]=T[1..p-k] S[k+1...P]=T[b...PP0+1]=T[1..pk]这部分是相等的。
    剩下的就暴力匹配即可。
    T [ p − k + 1 ] 和 S [ p + 1 ] T[p-k+1]和S[p+1] T[pk+1]S[p+1]开始。
    n e x t next next的时候等价于上面,唯一需要注意的是第一位必定是 l e n len len,所以第一位不要考虑。特判即可。
    匹配的时候只会进行超过 p p p的扩展,所以是线性算法。
int Next[maxn],extend[maxn];
char s[1000050],t[1000050];

void getNext(char* str){
    int i=0,j,pos,len=strlen(str);
    Next[0]=len;
    while(str[i]==str[i+1]&&i+1<len)i++;Next[1]=i;
    pos=1;
    for(int i=2;i<len;i++){
        if(Next[i-pos]+i<Next[pos]+pos){
            Next[i]=Next[i-pos];
        }
        else{
            j=Next[pos]+pos-i;
            if(j<0)j=0;//如果i比最远的的小,说明得从头开始。
            while(i+j<len&&str[j]==str[j+i])j++;Next[i]=j;
            pos=i;
        }
    }
}

void Exkmp(char* s,char* t){
    int i=0,j,pos,l1=strlen(s),l2=strlen(t);
    getNext(t);
    while(s[i]==t[i]&&i<l1&&i<l2)i++;extend[0]=i;
    pos=0;
    for(int i=1;i<l1;i++){
        if(Next[i-pos]+i<extend[pos]+pos)
            extend[i]=Next[i-pos];
        else{
            j=extend[pos]+pos-i;
            if(j<0)j=0;
            while(i+j<l1&&j<l2&&s[i+j]==t[j])j++;extend[i]=j;
            pos=i;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值