Lishengxie logo Lishengxie

Always on the way

  • 文章
  • 关于我
  • 归档
  • 联系
  1. 首页
  2. 文章
  3. LeetCode刷题 - KMP算法

LeetCode刷题 - KMP算法

2024-02-04 算法学习 Lishengxie

KMP算法是一种高效的字符串匹配算法,但是之前每次学过之后都会忘记,这次做一下总结加深印象,主要参考了以下链接。

  • https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html

问题

给定一个字符串s(长度为N)和一个模式串t(长度为M),如果s中存在t,那么返回模式串第一次出现的起始索引;如果不存在返回-1。对应Leetcode 28. 找出字符串中第一个匹配项的下标

KMP算法

KMP算法是由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现的一种快速的字符串匹配算法,时间复杂度为O(M+N)。KMP算法的核心思想是在字符串匹配失败时利用之前已经匹配的信息来做快速回退,避免从头再做匹配。KMP算法的核心函数是一个用于求解next数组的函数,next数组包含了模式串局部匹配的信息。

这里代码随想录中给出了关于next数组的详细解释。next数组对应自定义的前缀表,其中前缀表是一个和模式串长度相同的数组,前缀表第i个位置的值为[0,i]子字符串的最长相同前后缀的长度;

  • 前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串;
  • 举例来说,“aab”的前缀有“a”和“aa”、后缀有“b”和“ab”,“aabaa”的最长相同前后缀长度为2,“aa”的最长相同前后缀长度为1。

以下图为例,假设文本串和模式串分别为aabaabaafa和aabaaf,前缀表如图中所示。那么在b和f不匹配时,此时寻找前缀表中前一位存储的值,查找得到值为2,该值的含义是“aabaa”的最长相同前后缀长度为2,即“aa”。此时我们可以不用从头开始重新匹配,文本串中的匹配指针可以不移动,将模式串中的匹配指针回退到索引2处重新开始匹配即可。 prefix table

  • 这里为什么可以不回退文本串的匹配指针?

因为这里通过回退j指针,找到了从文本串中该位置向前的最长相同前后缀,获得了类似下图的效果。

prefix table
  • 实际使用中常通过将前缀表统一减1得到next数组,那么如何计算next数组?

next数组的计算类似于移动模式串,在模式串和模式串之间做匹配,在移动的过程中计算next数组的值,next数组的计算代码如下所示:

void getNext(int* next, const string& s){
    int j = -1;
    next[0] = j;
    for(int i = 1; i < s.size(); i++) { // 注意i从1开始
        while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
            j = next[j]; // 向前回退
        }
        if (s[i] == s[j + 1]) { // 找到相同的前后缀
            j++;
        }
        next[i] = j; // 将j(前缀的长度)赋给next[i]
    }
}
  • 基于next数组进行文本串和模式串的匹配代码如下:
void match(string s, string t) {
    int j = -1;
    int next[t.size()];
    getNext(next, t);

    for (int i = 0; i < s.size(); i++) {
        while (j >= 0 && s[i] != t[j+1]) {
            j = next[j];
        }
        if (s[i] == s[j+1]) {
            j++;
        }
        if (j == (t.size() - 1)) {
          return i - t.size() + 1;
        }
    }
    return -1;
}
算法 LeetCode KMP 字符串匹配

本文目录

  • 问题
  • KMP算法

精选文章

  • 分布式ID生成方案全解析:从数据库到雪花算法
  • Redis ziplist、quicklist 和 listpack
  • 多目标优化问题及两种常用解法

按主题探索

  • Redis 数据结构
    从存储布局理解实现
  • Linux 与部署
    服务器、证书与建站实践
  • 算法与深度学习
    解题方法、优化与公式推导
  • SNN / NoC 论文
    互连网络与映射算法

名言警句

学而时习之,不亦说乎?《论语·学而》学而不思则罔,思而不学则殆。《论语·为政》知之为知之,不知为不知,是知也。《论语·为政》三人行,必有我师焉。《论语·述而》工欲善其事,必先利其器。《论语·卫灵公》不积跬步,无以至千里。《荀子·劝学》千里之行,始于足下。《老子·第六十四章》纸上得来终觉浅,绝知此事要躬行。陆游《冬夜读书示子聿》
学而时习之,不亦说乎?
《论语·学而》 一言
← Transfer Server Nginx禁止使用IP直接访问服务器上相应端口 →

相关文章

  • 算法学习-差分数组 Dec 23, 2023
  • LeetCode刷题-二叉树遍历迭代法 Oct 17, 2023
  • LeetCode刷题 - 滑动窗口最大值 Oct 17, 2023
  • 多目标优化问题及两种常用解法 Apr 30, 2023
皖ICP备2023003716号-1 | 公安备案皖公网安备34012202341113 | 违法和不良信息举报邮箱:1141751053@qq.com
Powered by Hugo & Explore Theme & Theme by SimonAKing.