KMP

QUESTION:

有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢?

ANSWER:

KMP

step1:(真)前缀&(真)后缀

char pre suc pre suc
abc a,ab c,bc
abcba a,ab,abc,abcb a,ba,cba,bcba a
ababa a,ab,aba,abab a,ba,aba,baba a,aba
abcab a,ab,abc,abca b,ab,cab,bcab ab

nxt[i]P[0]~P[i1]presuc 中最长元素的长度

P a b a b a b c a
nxt -1 0 0 1 2 3 4 0

好了,解释清楚这个表是什么之后,我们再来看如何使用这个表来加速字符串的查找

e.g.

S="ababababca"
P="abababca"


如果在 j 处字符不匹配,那么由于前边所说的 P 字符串 nxt 的性质,

S[inxt[j]] ~ S[i1]=P[0] ~ P[nxt[j]1] (伪代码)

这是因为主字符串在 i 位失配,也就意味着

S[ij] ~ S[i1]=P[0] ~ P[j1] (伪代码)

在这个例子中就是

S[ij] ~ S[i1]=P[0] ~ P[j1]="ababab" (伪代码)

presuc 的最长元素为 "abab" ,长度为 4

所以就可以断言,(a)图中两个灰色部分是相同的,即长度为 4 的后缀与前缀相同。

这样一来,我们就可以将灰色字符段的比较省略掉。

具体的做法是:(即变为(b)图)

i=i;
j=nxt[j];

具体函数:

int KMP() {
int i = 0;
int j = 0;
while(i < S.size() && j < P.size()) {
if (j == -1 || S[i] == P[j])
i++;
j++;
} else {
j = nxt[j];
}
}
if (j == P.size())
return i - j;
else
return -1;
}

但是怎么求nxt?

SO EASY

nxt[i] 的过程完全可以看成字符串匹配的过程,即

newS=P;
newP=P.pre;//P的前缀皆可

一旦字符串匹配成功,那么当前的 nxt[i] 值就是 len(匹配)

具体来说,就是从P的第一位(注意,不包括第0位)开始对自身进行匹配运算。





void getNxt()
{
nxt[0] = -1;
int i = 0, j = -1;
while (i < P.size())
{
if (j == -1 || P[i] == P[j])
{
i++;
j++;
nxt[i] = j;
}
else
j = nxt[j];
}
}

D.E.Knuth
J.H.Morris
V.R.Pratt
三人联手打造KMP
KMP解决字符串匹配问题
(n为原串长度,m为匹配串长度)
蛮力算法:O(nm)
KMP:O(n+m)
KMP.png
若在匹配中在图中蓝色位置失配
则匹配串要右移(假设原串与蓝框不动)
因为目标是让匹配串全部匹配,所以右移后让匹配串全部匹配的必要条件图中绿框串相等(不相等的话直接GG)
为避免回溯,绿框大小尽可能大(但不碰蓝框),即右移位移少(保险)

理解如何求出nxt[i]

顺次扫描模式串P中每个元素,求出nxt[i]
当遍历到i+1时,nxt[1]nxt[i]均已经求出
如图O(Kn)求出即可(K为常数,图中相同颜色的矩形和相同的符号分别代表相同的子串和相同的字符)

posted @   ShaoJia  阅读(61)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示