一种O(n+m)复杂度的字符串匹配算法,复杂度是很优秀的。
我们来看看kmp算法具体思路:就是不移动回移主串p的位置,进行匹配,只移动模式串t的位置。首先我们知道如果p[j] == t[k],那么就 j++ , k++; 如果p[j] != t[k];按照kmp的思路就是回退k的位置,j不移动,那么怎么回退成了这个算法的关键。
定义next[j] = k,代表含义t[0 – k-1] == t[j-1 – j-k+1]匹配;而且是最大长度的匹配,网上有的称作k为最大公共前缀后缀串长度,反正你理解就好,反正公式在上面已经给出,无所谓称呼。如果要暴力求解这个next[j]就是以t[0]为起点枚举长度i的前缀,和以t[j-1]为终点长度同样为i的后缀是否匹配,然后求一个最大长度,我这样只是方便理解。
高手一般不暴力,只dp;那么我们dp求解
next[j] = k ; 如果t[k] == p[j];那么next[j+1] = k + 1;
这个很好理解吧,因为t[0 – k-1] == t[j-1 – j-k+1]已经匹配了(next[j] = k);如果t[k] == t[j];那么next[j+1] = k + 1没什么问题;
关键是如果t[k] != t[j];怎么办;网上好多解释,我反正都没怎么看懂。我的解释就是:
如果我们枚举长为x,我们把最后一个端点拿出来,分别比较
t[0 – x-2] 和 t[j-1 – j-x+2] 还有 t[x] 与 t[j],你发现一个细节吗;
因为我们已知next[j] = k;意味着t[0 – k-1] 与 t[j-1 – j-k+1]已经匹配了,那么t[j-1 – j-x+2] 是不是等于 t[k-x+2 – k-1];那么就是在求一个next[k],如果t[x] == t[j],next[j+1] = next[k] + 1; 所以有k = next[k]。
最关键的讲完了。
上代码,以下是优化的next数组求解;
至于还有哪里可以优化,举个栗子:ABAB的next数组,[-1,0,0,1]
如果j == 3不匹配了,它会跳到 j ==1;然而这也肯定不匹配,因为t[j] == t[next[j]];所以才有了优化。
void Getnext(int next[],String t)
{
int j=0,k=-1;
next[0]=-1;
while(j<t.length-1)
{
if(k == -1 || t[j] == t[k])
{
j++;k++;
if(t[j]==t[k])
next[j] = next[k];
else
next[j] = k;
}
else k = next[k];
}
}