Leetcode 28. 找出字符串中第一个匹配项的下标
1.题目基本信息
1.1.题目描述
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
1.2.题目地址
https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/
2.解题方法
2.1.解题思路
KMP匹配算法
2.2.解题步骤
第一步,构建模式串的最长相同前后缀数组pmArr
-
1.1.设置需要的数据结构,一个存储pmArr元素的数组、不后退的从1开始的指针i、i-1处元素结尾的最长前后缀的长度
-
1.2.指针i勇往直前,直至模式串的结尾。在过程中,如果i处的值等于i-1处的最长相同前缀后的一个元素,则更新prefixLen和pmArr数组;如果不相等,且上一个最长相同前后缀的长度为0,说明是初始化情况或者递推到这里了,这种情况i处元素结尾的最长相同前后缀的长度为0,更新pmArr数组;如果不相等,且上一个最长相同前后缀的长度不为0,需要缩减上一个最长前后缀长度,将其缩减为上一个最长相同前后缀的最长相同前后缀,根据pmArr的前置的信息更新prefixLen。
第二步,根据pmArr数组进行子串匹配。让i和j指针分别指向被匹配串和模式串的元素,i指针不后退的遍历主串。过程中,如果i和j指向的元素值相同,i和j指针同时向前走一步;如果不相等,且j指针指向模式串的开头,则i指针前进一位;如果不相等,且j指针没有指向模式串的头部,则根据从pmArr中取出的j-1处元素结尾的最长前后缀的长度,并以此更新j的指针位置。如果过程中j等于模式串的长度,说明匹配成功,直接返回下标。
3.解题代码
python代码
class Solution:
# KMP算法
def strStr(self, haystack: str, needle: str) -> int:
# 第一步,构建模式串的最长相同前后缀数组pmArr
# 1.1.设置需要的数据结构,一个存储pmArr元素的数组、不后退的从1开始的指针i、i-1处元素结尾的最长前后缀的长度
pmArr=[0] * len(needle)
prefixLen = 0
i = 1
# 1.2.指针i勇往直前,直至模式串的结尾。在过程中,如果i处的值等于i-1处的最长相同前缀后的一个元素,则更新prefixLen和pmArr数组;如果不相等,且上一个最长相同前后缀的长度为0,说明是初始化情况或者递推到这里了,这种情况i处元素结尾的最长相同前后缀的长度为0,更新pmArr数组;如果不相等,且上一个最长相同前后缀的长度不为0,需要缩减上一个最长前后缀长度,将其缩减为上一个最长相同前后缀的最长相同前后缀,根据pmArr的前置的信息更新prefixLen。
while i < len(needle):
if needle[i] == needle[prefixLen]:
prefixLen += 1
pmArr[i] = prefixLen
i += 1
else: # 不匹配
if prefixLen == 0:
i += 1
else:
# 关键点,理解+记忆
prefixLen = pmArr[prefixLen - 1]
# print("t1", pmArr)
# 第二步,根据pmArr数组进行子串匹配。让i和j指针分别指向被匹配串和模式串的元素,i指针不后退的遍历主串。过程中,如果i和j指向的元素值相同,i和j指针同时向前走一步;如果不相等,且j指针指向模式串的开头,则i指针前进一位;如果不相等,且j指针没有指向模式串的头部,则根据从pmArr中取出的j-1处元素结尾的最长前后缀的长度,并以此更新j的指针位置。如果过程中j等于模式串的长度,说明匹配成功,直接返回下标。
i = j = 0
while i < len(haystack):
if haystack[i] == needle[j]:
i += 1
j += 1
else: # 不匹配
if j == 0:
i += 1
else:
j = pmArr[j - 1]
# 匹配成功条件
if len(needle) == j:
return i - j
return -1