算法刷题打卡第39天:找出字符串中第一个匹配项的下标---KMP算法

找出字符串中第一个匹配项的下标

难度:中等
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。

示例 1:

输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 06 处匹配。
第一个匹配项的下标是 0 ,所以返回 0

示例 2:

输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1

KMP算法

思路:
KMP算法是一种改进的字符串匹配算法,由 D.E.KnuthJ.H.MorrisV.R.Pratt 提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个 next() 函数实现,函数本身包含了模式串的局部匹配信息。

这次就不自己写算法详解了(代码实现有点不太好理解),想要学习的小伙伴可以参考以下内容:

  • KMP算法原理快速理解可以参考此处b站教程:KMP算法易懂版
  • KMP算法详细实现流程可以参考此处:简单题学 KMP 算法
  • next函数详细解析可以参考此处b站教程 :KMP算法之求next数组代码讲解

时间复杂度: O ( n + m ) O(n+m) O(n+m),其中 n n n 是字符串 haystack \textit{haystack} haystack 的长度, m m m 是字符串 needle \textit{needle} needle 的长度。我们至多需要遍历两字符串一次。
空间复杂度: O ( m ) O(m) O(m),其中 m m m 是字符串 needle \textit{needle} needle 的长度。我们只需要保存字符串 needle \textit{needle} needle 的前缀列表 n e x t next next

class Solution:
    def strStr(self, haystack, needle):
        def kmp(s, p):
            s_len, p_len = len(s), len(p)
            # 获取next数组
            next_lis = kmp_next(p, p_len)
            i, j = 0, 0
            # 如果i大于等于主串长度,则返回-1
            while i < s_len:
                # 如果为-1则说明没有第一个字符都没有匹配到,所以需要从下一个字符开始匹配模式串首个字符
                # 如果相等那么两个下标都向后移动继续匹配
                if j == -1 or s[i] == p[j]:
                    j += 1
                    i += 1
                # 如果不相等,也不是头部,则需要回溯模式串的下标进行匹配,与构建next的回溯一样
                else:
                    j = next_lis[j]
                # 判断是否以及找到匹配子串,如果找到则返回下标
                if j == p_len:
                    return i - j
            return -1
                
        def kmp_next(p, length):
            # 初始化next数组
            next_lis = [-1] * length
            # 错位模式串用来求next数组
            i, j = 0, -1
            # 只求前m-1个,next数组为前缀数组向后偏移1
            while i < length - 1:
                # 如果j回溯到数组头或者相等的情况,更新next数组
                if j == -1 or p[j] == p[i]:
                    j += 1
                    i += 1
                    next_lis[i] = j
                # 回溯j快速求和结果(重点,难理解)
                else:
                    j = next_lis[j]
            return next_lis
        return kmp(haystack, needle)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string

你可能感兴趣的:(躺平合集,算法,python,leetcode,KMP算法)