算法练习day9

5

示例:

文本串:aabaabaaf

匹配串:aabaaf。

KMP算法

关于NEXT数组(前缀表)

(参考了KMP算法的前缀next数组最通俗的解释,如果看不懂我也没辙了-CSDN博客和卡哥的讲解,自己的一些理解)

  • 前缀表在文本串中,是用来回退的,记录了模式串与文本串不匹配时,模式串应该从哪里开始重新匹配
  • 前缀表在模式串中,记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。
  • (卡哥的文章里说的)

字符串匹配时,字符串的对称指的是一块一块相同。卡哥提到的前缀子串和后缀字串相同,其本质就是分别从头和从尾开始对比,查看是否有相同的部分,也对应了一块一块相同。

例子探究

(以aabaaf为例,写出NEXT数组)

理解这个NEXT数组,需要了解字符串内的情况。既然卡哥提到了前缀和后缀,那么讲前缀集和后缀集写出来。划出每个字串下前后缀集中相同元素与NEXT数组的关系。

image-20240516155633288

  • 这里刚开始犯了错误,以为是看集合相同元素的个数。。但是这个相同元素的个数又实在是想不出来和前面的对称程度有什么联系。。。
  • 因此假设最后,字符串是aabaab,让样例在变多一点。
  • image-20240516164354767
  • NEXT[5]应该是3,NEXT数组的值和相同前后缀集相同元素的最长长度有关。

前缀都是从都是从字符串第0位开始的(即前缀的第一位),后缀都是从字符串第len-1位结尾。

前缀和后缀的长度一致才有可能前后缀相同,如果前后缀相同,此时就会出现一块和一块是一样的,这里就和“对称”的定义对上了。此时相等前后缀的长度就是“对称程度”。

优化

像我的草稿中从头一个个找,是暴力搜索的做法,这种做法可以得到NEXT数组,但是复杂度很高,得优化。

优化的思路就是那篇大佬文章中说的,观察前一个字符的对称程度:

  • 假设已经知道了字符i前字串的最大相同前后缀子串长度为n。那么现在加一个字符i,这个i到底能不能增加此时字串的最大相同前后缀子串长度呢?假设字符i为t

    1. 若此前的字符串为(abc)dt(abc),明显没有“对称”了,为什么?
      kom(abcdtabc**t**)肉眼上看是没有重复的块了(后缀一定包含增加的这个t)。
      只有当这个字符串为kom(abct)d(abct)时才会“对称”。

    2. (abc)dt(abc) 和 kom(abc)td(abc)为什么会截然不同?
      这是因为前者的第4个字符是d,后者是t。
      当第4个字符和t相同时,此时的对称程度就是4了。反之就是0。
      因为前一个字符时,对称程度已经是3了,此时如果前缀abc后面的字符也是t,那么相同前后缀字串就会变长,否则因为一定要带上t就会变成0。

  • 总结起来可以认为,要看包含当前字符下的最大相同前后缀字串的长度,一个便利的方法是通过它前面的字符的对称长度(最大相同前后缀字串长度)。

  • 拿这个字符和前一个字符记录的对称程度的相同前后缀子串中的前缀子串的下一位对比。前一个字符记录的……写起来都很拗口,其实根据前缀和后缀