代码随想录训练营Day9|KMP字符串匹配

KMP算法基础

  • 主要应用:在字符串匹配上。
  • 主要思想:匹配过程中,当出现不匹配的字符时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。
  • 什么是前缀:是指不包含最后一个字符的所有以第一个字符开头的连续子串。比如字符串"aab"的前缀有:a,aa。
  • 什么是后缀:是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
    比如字符串"aab"的后缀有:b,ab。
  • 什么是最长相同前后缀:字符串"aab"的前、后缀不存在相同的字符串,所以最长相同前后缀长度为0。
  • 什么是前缀表:字符串从索引 i = 0 开始,统计 0 ~ i (包括i) 的字符串中最长相同前后缀组成的数组。

举例:字符串 "aabaaf"
详细过程:
i = 0, 字符串为 a,最长相同前后缀长度为 0
i = 1, 字符串为 aa,前缀:a,后缀:a,存在1个相同的前后缀,则最长相同前后缀长度为 1
i = 2, 字符串为 aab,前缀:a,aa,后缀:b,ab,不存在相同的前后缀,则最长相同前后缀长度为 0
i = 3, 字符串为 aaba,前缀:a,aa,aab,后缀:a,ba,aba,存在 1 个相同的前后缀 a,则最长相同前后缀长度为 1
i = 4, 字符串为 aabaa,前缀:a,aa,aab,aaba,后缀:a,aa,baa,abaa,存在 2 个相同的前后缀 a 和 aa,则最长相同前后缀为 2
i = 5, 字符串为 aabaaf,前缀:a,aa,aab,aaba,aabaa,后缀:f,af,aaf,baaf,abaaf,存在 0 个相同的前后缀,则最长相同前后缀为 0
所以其前缀表为 [0, 1, 0, 1, 2, 0]

  • 前缀表的作用

举例:文本串"aabaabaafa",模式串"aabaaf"


image.png

如图,当匹配到下标 i = 5时,当出现 b 和 f 不匹配的字符时,下一步可以直接跳到下标为 2 的位置继续匹配。
至于为什么是跳转到下标为2的位置,是根据前缀表来的
下标5之前这部分的字符串(也就是字符串aabaa)的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面重新匹配就可以了。

  • 如何构建前缀表
    实现一
  1. 初始化两个指针 i = 0, j = -1,数组 next = [j];
    其中 i 指向后缀末尾位置,j 指向前缀末尾位置;
    比如i = 2,指向字符b,已经匹配过的字符串为 aab,此时 i 指向后缀末尾即字符b,j 指向前缀末尾即字符a;
  2. 处理前后缀不相同的情况
  3. 处理前后缀相同的情况

28. 找出字符串中第一个匹配项的下标

解题思路
var strStr = function(haystack, needle) {
    if (needle.length === 0) {
        return 0;
    }
    // 初始化j=-1
    let j = -1;
    let next = []
    next.push(j);
    // 遍历模式字符串
    for (let i = 1; i < needle.length; i++) {
        // 前后缀不相同
        while(j >= 0 && needle[i] !== needle[j+1]) {
            j = next[j] // 向前回退
        }
        // 前后缀相同
        if (needle[i] === needle[j+1]) {
            j++
        }
        next.push(j)
    }
    j = -1;
    for (let i = 0; i < haystack.length; i++) {
        while(j >= 0 && haystack[i] !== needle[j+1]) {
            j = next[j]
        }
        if (haystack[i] === needle[j+1]) {
            j++
        }
        if (j == (needle.length - 1) ) { // 文本串s里出现了模式串t
            return (i - needle.length + 1);
        }
    }
    return -1
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 代码随想录第九天,继续字符串 今日任务 ● 28. 实现 strStr() 28. 找出字符串中第一个匹配项的下...
    沧海日月阅读 1,046评论 0 0
  • 链接:实现 strStr()[https://leetcode-cn.com/problems/implement...
    EasonRiver阅读 2,383评论 0 0
  • 在字符串系列的算法中,KMP算法属于较难的一个。实际上它的代码并不多,主要一些细节的地方难以理解,再加上书上,网上...
    zero_sr阅读 5,713评论 0 9
  • 引言 大一下参加学校ACM预备队集训的时候首次接触KMP算法,当时看了很多介绍文章,仍然不是很理解其实质,只是简单...
    FEZ_8ac2阅读 1,612评论 0 1
  • 字符串匹配 假设有两个串s和p,字符串匹配就是在s中查找与p相同的子串的操作。将s称为目标串,p称为模式串。 BF...
    Pin_yu阅读 3,785评论 0 0