KMP算法

KMP算法,通常用于在一个文本字符串中查找匹配P的出现位置和出现次数

动画展示

​编辑

步骤说明

  • 步骤一
    判断此时的i,j是否超出各自字符串的限制:

    • 若j超出P的限制则退出并返回匹配成功处的位置下标,表示完成了子串的完整匹配

    • 若i超出S的限制,则退出并说明无解

    • 比较S[i],P[j]:

      • 若S[i]==P[j]或者j==−1或者j ==−1,则i++,j++,重复步骤一
      • 若S[i]≠P[j],进入步骤二
  • 步骤二
    失配时,i不变,j=ne[j],进入步骤一

Q:ne数组是怎么生成的?

ne数组每次移动的前面字串中找最长前后缀

假设一个 模式串 长度为n,则存在n个前缀与n个后缀,舍去其中长度为n的情况,则剩下n−1个前缀与n−1个后缀,前缀与后缀的最大匹配就是该字符串的最长公共前缀后缀长度, ne[i]代表的就是前i个字符组成的子串中,最长公共前后缀的长度

当失配时,j=ne[j],充分利用已知信息,找出模式串中最值得再次匹配的位置

求ne数组和kmp很相似,相当于自己找自己的匹配串ne[1]=0;下标从2开始,紧扣定义。

    // 一、求ne数组
    // i:当前试图进行匹配的S串字符,j+1是模板串当前试图与S串i位置进行匹配的字符
    // j:表示已匹配的长度,一直都在尝试让j+1位和i位进行匹配,退无可退,无需再退。
    // i:是从2开始的,因为ne[1]=0,表示第1个不匹配,只能重头开始,不用算
    for (int i = 2, j = 0; i <= n; i++) {
        while (j && p[i] != p[j + 1]) j = ne[j];
        // 如果是匹配情况发生了,那么j移动到下一个位置
        if (p[i] == p[j + 1]) j++;
        // 记录j到ne数组中
        ne[i] = j;
    }

    // 二、匹配字符串
    // i:当前试图进行对比的S串位置
    // j:最后一个已完成匹配的P串位置,那么,当前试图与S串当前位置i进行尝试对比匹配的位置是j+1
    for (int i = 1, j = 0; i <= m; i++) {
        while (j && s[i] != p[j + 1]) j = ne[j]; // 不行就退吧,当j==0时,表示退无可退,无需再退
        // 如果是匹配情况发生了,那么j移动到下一个位置
        if (s[i] == p[j + 1]) j++; // 匹配则指针前行,i不用++,因为它在自己的for循环中,自带++
        if (j == n) {              // 如果匹配到最大长度,说明完成了所有位置匹配
            printf("%d ", i - n);  // 输出开始匹配位置
            j = ne[j];             // 回退,尝试继续进行匹配,看看还有没有其它可以匹配的位置
        }
    }

以上学习自ACwing和AcwingKPM题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ˇasushiro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值