此博客为《代码随想录》字符串章节的学习笔记,主要内容为字符串匹配 KMP 算法相关的题目解析。
文章目录
- [28. 找出字符串中第一个匹配项的下标](#28. 找出字符串中第一个匹配项的下标)
- [459. 重复的子字符串](#459. 重复的子字符串)
28. 找出字符串中第一个匹配项的下标
python
class Solution:
def getNext(self, s: str) -> List[int]:
j, nxt = 0, [0] * len(s)
for i in range(1, len(s)):
while j > 0 and s[i] != s[j]:
j = nxt[j - 1]
if s[i] == s[j]:
j += 1
nxt[i] = j
return nxt
def strStr(self, haystack: str, needle: str) -> int:
j, nxt = 0, self.getNext(needle)
for i in range(len(haystack)):
while j > 0 and haystack[i] != needle[j]:
j = nxt[j - 1]
if haystack[i] == needle[j]:
j += 1
if j == len(needle):
return i - j + 1
return -1
getNext
用于计算next
数组,next
数组是模式串的特征规律,与文本串无关- 在此代码中的
next
数组的定义下,每次遇到矛盾,都需要查找上一个元素 在next
数组中的值,以确定回溯位置 getNext
函数中 j 表示的是目前最长公共前后缀的长度(也指向着公共前缀的末尾);i 指向着公共后缀的末尾getNext
的 for 循环:i 从 1 开始 ,因为 i 为 0 时表示着长度为 1 的串,最长公共前后缀长度为 0,即next[0] = 0
(在数组初始化时已经完成)strStr
的 for 循环:i 从 0 开始 ,完整遍历文本串haystack
459. 重复的子字符串
python
class Solution:
def getNext(self, s: str) -> List[int]:
j, nxt = 0, [0] * len(s)
for i in range(1, len(s)):
while j > 0 and s[i] != s[j]:
j = nxt[j - 1]
if s[i] == s[j]:
j += 1
nxt[i] = j
return nxt
def repeatedSubstringPattern(self, s: str) -> bool:
nxt = self.getNext(s)
if nxt[-1] != 0 and len(s) % (len(s) - nxt[-1]) == 0:
return True
return False
- 如果字符串 s 是由重复子串组成,那么最长相等前后缀不包含的子串 一定是 s 的最小重复子串,证明过程
- 因此仿照 KMP 算法计算
next
数组,判断是否存在最长相等前后缀,以及最长相等前后缀不包含的子串的长度len(s) - nxt[-1]
,是否能够被原字符串长度整除
移动匹配法(通用做法)
python
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
s_ = (s + s)[1:-1]
return s in s_
- 自身加自身得到
s_
,之后移除第一和最后一个元素(破坏原始串),判断s_
中是否包含自身s