今日任务:
今日心情:意识到了写博客的重要性,能够快速帮我回溯记忆。
资料来源:
KMP是一种针对字符串的算法,因为发明者为Knuth,Morris和Pratt三位学者,所以取名KMP。它的作用是当字符串匹配失败时,在下一次的匹配中能够获取部分已经匹配的字符串,从而避免再次从头开始匹配。如果是用暴力来在字符串中寻找匹配字符串,那么显而易见就是两轮循环,KMP可以利用最长相等前后缀来减少循环次数。
以字符串aabcdaa
为例,它的所有前缀包括:
同理,所有后缀包括:
在这些前后缀中,最长相同前后缀即为aa
,长度为2。
前缀表,即为字符串的所有前缀的下标和最长相同前后缀的长度组成的表,还是以字符串aabcdaa
为例,它的前缀表是这样的:
字符 | a | a | b | c | d | a | a |
---|---|---|---|---|---|---|---|
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
最长相同前后缀的长度 | 0 | 1 | 0 | 0 | 0 | 1 | 2 |
以在字符串aabaabaafaab
(文本串,变量名一般是haystack
)中匹配aabaaf
(模式串,变量名一般是needle
)为例。
求模式串的前缀表
字符 | a | a | b | a | a | f |
---|---|---|---|---|---|---|
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
最长相同前后缀的长度 | 0 | 1 | 0 | 1 | 2 | 0 |
开始循环匹配,每次匹配失败后,文本串从匹配失败后的位置开始,模式串以匹配失败的位置的前一个元素在前缀表中存储的最长相同前后缀的长度为下标开始下次匹配,直到匹配成功。
KMP能提升速度的原因在于,比起暴力两层循环,KMP需要的是对模式串的一次循环和实际匹配过程中的一次循环。后一次循环还能靠前缀表来减少匹配次数。KMP的时间复杂度是,这比暴力的要快多了。
前缀表的含义是每一个字串前后相同字符的长度,它代表了KMP最根本的目的:在下一次的匹配中能够获取部分已经匹配的字符串。前缀表所存储的最长相同前后缀就是这句话中的“部分已经匹配的字符串”。因为最长相同前后缀的含义,下一次循环开始时,在这次匹配点之前的字符都不再需要匹配,只需要从上一次循环匹配失败的点再次开始即可。
字符串,在大部分的语言中的底层实现都是基于类似字符数组的形式。在用python解题时,更应该将其转换为List[str]
,一个字符一个字符组成的列表来处理。
注
预留Java字符串的底层机制
注
预留Go字符串的底层机制
双指针是个极其广泛的解法类型,它的最终目标是利用好两个指针,在一次循环内完成两次循环要做的事情。
基本上粗体的就是我一开始想不到,并且预感自己绝对会忘的东西😂
本文作者:御坂19327号
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!