KMP算法
KMP算法
Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个字符串S内查找一个词W的出现位置。一个词在不匹配时本身就包含足够的信息来确定下一个匹配可能的开始位置,此算法利用这一特性以避免重新检查先前配对的字符。
这个算法由高德纳和沃恩·普拉特在1974年构思,同年詹姆斯·H·莫里斯也独立地设计出该算法,最终三人于1977年联合发表。
前缀函数的定义
给定一个长度为
其中
- 如果长度为
的子串 有一对相等的真前缀与真后缀: 和 ,那么 就是这个相等的真前缀(或者真后缀)的长度,即 ; - 如果不止有一对相等的,那么
就是其中最长的那一对的长度; - 如果没有相等的,那么
。
简单来说
用数学语言描述如下:
特别地,规定
举例
例如,对于字符串
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 2 | 3 | 0 |
其中,因为
这里,我们直接给出前缀函数的计算方法:
def prefix_function(s: str): n = len(s) pi = [0] * n for i in range(1, n): while j > 0 and s[i] != s[j]: j = pi[j - 1] if s[i] == s[j]: j += 1 pi[i] = j return pi
其中,时间复杂度为:
前缀函数的应用
KMP算法
给定一个长度为
的文本 和一个长度为 的字符串 ,找到并展示 在 中的所有出现(occurrence)。
利用前面的前缀函数计算方法,我们直接给出KMP算法对其应用:
def kmp(text: str, pattern: str): m, n = len(text), len(pattern) pi = prefix_function(pattern) j = 0 for i in range(m): while j > 0 and text[i] != pattern[j]: j = pi[j - 1] if text[i] == pattern[j]: j += 1 if j == n: return i - n + 1 return -1
其中,时间复杂度为:
统计每个前缀的出现次数
问题1:给定一个长度为
的字符串 ,在问题的第一个变种中我们希望统计每个前缀 在同一个字符串的出现次数。
问题2:给定一个长度为
的字符串 ,统计每个前缀 在另一个给定字符串 中的出现次数。
def count(): ans = [0] * (n + 1) for i in range(0, n): ans[pi[i]] += 1 for i in range(n - 1, 0, -1): ans[pi[i - 1]] += ans[i] for i in range(0, n + 1): ans[i] += 1
字符串压缩
应用
应用1:Leetcode
题目
分析
参考前面的KMP算法实现即可。
构造
代码实现
class Solution: def strStr(self, haystack: str, needle: str) -> int: m, n = len(needle), len(haystack) if m == 0: return 0 _next = [0] * m j = 0 for i in range(1, m): while j > 0 and needle[i] != needle[j]: j = _next[j - 1] if needle[i] == needle[j]: j += 1 _next[i] = j j = 0 for i in range(n): while j > 0 and haystack[i] != needle[j]: j = _next[j - 1] if haystack[i] == needle[j]: j += 1 if j == m: return i - m + 1 return -1
参考:
本文作者:LARRY1024
本文链接:https://www.cnblogs.com/larry1024/p/17238834.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步