浅谈扩展KMP

扩展KMP问题

给定母串 s ,和子串t,定义 n=|s|m=|t| , extendi=s[i..n]textend

引例

s=aaaaabaa
t=aaaaaa
首先通过六次运算,我们得到了 extend1=5 ,接下来我们要计算 extend2 ,那是不是也要计算五次?在计算 extend1 之后我们得到这样的信息 s[2..5]=t[2..5] ,在计算 extend2 的时候其实是 s[2..n] 在匹配t,又因为 s[2..5]=t[2..5] ,那么在匹配的开头阶段就是以 t[2..5] 为母串,t为子串的匹配。

next数组的引入

定义 nexti 表示 t[i..m]t 对上述例子, next2=5 ,可以得到 t[1..5]=t[2..6]t[1..4]=t[2..5] ,
又因为 s[2..5]=t[2..5],s[2..5]=t[1..4], 也就是说前四位的匹配是完全可以避免的。

进入正题

提出更加一般的算法,假设此时1到k中的 extendi (黄色部分)已经算法算好,设 p=max{i+extendi1}1ik,ai ,
如下图:
这里写图片描述
我们可以得到
s[a..p]=t[1..pa+1]s[k+1..p]=t[ka+2..pa+1],l=nextka+2
此时会有两种情况
这里写图片描述
上面的红色部分是相等的,
(因为 s[k+1..p]=t[ka+2..pa+1],lnextka+2 ),但蓝色部分肯定不相等
(如果相等,那么 t[1..l+1]=s[k+1..k+l]=t[ka+2..pa] ,那么此时 nexti=next1+1 ,矛盾),
结论:所以我们无需比较,即可知道 nextk+1=l
这里写图片描述
紫色的位置以及以后的位置都是未被探知的,所以此时就要从 s[p+1]t[pk+1]ak+1
next数组的求法与extend的求法类似,具体看代码。
代码:

var
        next,extend:array[0..1000000]of longint;
        s,t:ansistring;
        i,j,a,l,lx,p:longint;
function max(i,j:longint):longint;
begin
        if i<j then max:=j else max:=i;
end;
begin
        readln(t);
        readln(s);
        j:=0;
        while (2+j<=length(t))and(t[1+j]=t[2+j]) do inc(j);
        next[1]:=length(t);
        next[2]:=j;
        a:=2;
        for i:=3 to length(t) do
        begin
                p:=a+next[a]-1;
                l:=next[i-a+1];
                if l<p-i+1 then//自己**仔细**体会(对比上文)
                        next[i]:=l
                else
                begin
                        j:=max(0,p-i+1);
                        while (i+j<=length(t))and(t[i+j]=t[1+j]) do inc(j);
                        next[i]:=j;
                        a:=i;
                end;
        end;
        j:=0;
        while (j<length(S))and(j<length(t))and(t[1+j]=S[1+j]) do inc(j);
        extend[1]:=j;
        a:=1;
        for i:=2 to length(s) do
        begin
                p:=a+extend[a]-1;
                l:=next[i-a+1];
                if l+i<p+1 then
                        extend[i]:=l
                else
                begin
                        j:=max(0,p-i+1);
                        while(i+j<=length(S))and(j<length(t))and(S[i+j]=t[1+j]) do inc(j);
                        extend[i]:=j;
                        a:=i;
                end;
        end;
end.

the end

由于我的水平有限,难免会有些写错的地方,希望大家批评指正,多多包容,thank you for your patience.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值