西元算法学习笔记之KMP算法

KMP算法的目的是实现在文本中对某一字符串的快速查找。

先来看一下朴素做法:

string s, p;
for(int i = 1; i <= s.size() - p.size(); i ++ ){
    int flag = 1;
    if(s[i] == p[1])
        for(int j = 1; j <= p.size(); j ++ )
            if(s[i + j] != p[j + 1]){ 
                flag = 0;
                break;
            }
    if(flag == 1) cout << i << endl;
}
    

下面就是思考该如何对朴素做法进行优化。

找到开始比较的坐标是必要的,而逐个字母进行比较似乎也必不可少,那么唯一可以利用的就是每次比较失败后得到的信息

下面通过例子来说明:(默认字符串从1开始)

字符串s:abababc

字符串p:ababc

如下图,从s[1]开始匹配,匹配到s[5]失败,接下来关键的一步是从s[3]开始匹配

通过这一步操作,我们就跳过了s[1],实现了优化。

这一步的原理便是整个KMP算法的灵魂。而这个原理则可以描述为:

对于不同的模式串p[ ],在不同匹配失败的位置最大可以跳过的距离该如何计算?

由上述问题,我们应当计算出对于p[i],最大可以跳过的距离next[i]

next[i] = j直观解释为 p[1] ~ p[ j ] 这一段与 p[ i - j + 1] ~ p[ i ] 这一段相等 

实际上就是p[1~i]的最长相等前后缀的长度为j

之后的问题就是对next[ ]数组的求解,我们考虑next[ ]数组的递推关系

s[]是长文本,p[]是模式串,n是s的长度,m是p的长度
求模式串的Next数组:
for(int i = 2, j; i <= n; i ++ ){
        if(p[ne[i - 1] + 1] == p[i]) ne[i] = ne[i - 1] + 1;
        else{
            j = ne[i - 1];
            while(j && p[j + 1] != p[i]) j = ne[j]; 
            if(!j) ne[i] = 0;
            else ne[i] = j + 1;
        }
    }

求出next[ ]数组后便是最后匹配的过程,代码如下:

for (int i = 1, j = 0; i <= n; i ++ )
{
    while (j && s[i] != p[j + 1]) j = ne[j];
    if (s[i] == p[j + 1]) j ++ ;
    if (j == m)
    {

        匹配成功后的逻辑
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值