题目描述:
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
题解:
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
p, q = 0, 0
n = len(needle)
m = len(haystack)
while p < m and q < n:
if needle[q] == haystack[p]:
p += 1
q += 1
else:
p = p - q + 1 # 回溯到上一个匹配的位置的下一个字符
q = 0
if q == n:
return p - q
else:
return -1
思路:
-
双指针: 使用两个指针
p
和q
分别表示在haystack
和needle
中当前比较的位置。 -
循环比较: 在循环中,比较
haystack[p]
和needle[q]
是否相等。如果相等,两个指针都向前移动;如果不相等,需要回溯到上一个匹配的位置的下一个字符,并将q
重置为 0。 -
回溯: 回溯的位置是
p = p - q + 1
,即将p
移动到上一个匹配位置的下一个字符。 -
判断匹配: 在循环结束后,检查
q
是否等于needle
的长度。如果相等,说明完全匹配,返回起始位置p - q
;否则,返回 -1 表示未找到匹配的子串。
KMP算法:
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if not needle:
return 0 # 如果 needle 为空,返回 0
def build_kmp_table(pattern):
table = [0] * len(pattern)
j = 0
for i in range(1, len(pattern)):
while j > 0 and pattern[i] != pattern[j]:
j = table[j - 1]
if pattern[i] == pattern[j]:
j += 1
table[i] = j
return table
m, n = len(haystack), len(needle)
if m < n:
return -1 # 如果 haystack 长度小于 needle 长度,直接返回 -1
kmp_table = build_kmp_table(needle)
i, j = 0, 0
while i < m:
if haystack[i] == needle[j]:
i += 1
j += 1
if j == n:
return i - n # 如果 j 等于 needle 长度,说明完全匹配,返回起始位置
else:
if j > 0:
j = kmp_table[j - 1] # 根据部分匹配表进行回溯
else:
i += 1
return -1 # 没有找到匹配
思路:
1. 构建 KMP 表
build_kmp_table
函数用于构建部分匹配表(PMT)。PMT 用于优化模式串的匹配过程,避免不必要的字符比较。
- 初始化数组
table
,用于存储部分匹配表。 - 使用两个指针
i
和j
,从模式串的第二个字符开始遍历。 - 在循环中,如果当前字符匹配,增加
j
和i
。如果不匹配,根据部分匹配表进行回溯。 - 最终,
table[i]
存储了模式串中以第i
个字符结尾的最长相等前缀和后缀的长度。
2. 使用 KMP 算法进行匹配
strStr
函数使用 KMP 算法在文本串中查找模式串的第一个匹配项。
- 如果模式串为空,直接返回 0(空串在任何字符串的开头都是匹配的)。
- 调用
build_kmp_table
构建部分匹配表。 - 使用两个指针
i
和j
分别遍历文本串和模式串。 - 在循环中,如果当前字符匹配,增加
i
和j
。如果j
等于模式串长度,说明完全匹配,返回起始位置i - n
。 - 如果当前字符不匹配,根据部分匹配表进行回溯。如果
j > 0
,将j
设置为部分匹配表的值;否则,增加i
。 - 如果循环结束后没有找到匹配,返回 -1。