算法刷题打卡第35天:找出字符串中第一个匹配项的下标【BF/RK/BM】

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

难度:中等
给你两个字符串 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

解法一、BF算法

思路:
逐字符地进行匹配(比较 A [ i ] A[i] A[i] B [ j ] B[j] B[j]),如果当前字符匹配成功( A [ i ] = = B [ j ] A[i]==B[j] A[i]==B[j] ),就匹配下一个字符( + + i , + + j ++i,++j ++i++j),如果失配, i i i 回溯, j j j 置为 0 0 0 ( i = i − j + 1 , j = 0 i=i-j+1,j=0 i=ij+1j=0)。

时间复杂度: O ( m ∗ n ) O(m*n) O(mn),与主串和模式串的长度都正相关
空间复杂度: O ( 1 ) O(1) O(1)

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        needle_length = len(needle)
        for i in range(len(haystack) - needle_length + 1):
            for x, y in zip(haystack[i:i+needle_length], needle):
                if x != y:
                    break 
            else:
                return i
        return -1

解法二、RK算法

思路:
对于给定文本串 h a y s t a c k haystack haystack 与模式串 n e e d l e needle needle,通过滚动哈希算快速筛选出与模式串 n e e d l e needle needle 不匹配的文本位置,然后在其余位置继续检查匹配项。此处采用 o r d ord ord 函数代替hash,数字较小便于计算。

时间复杂度: O ( n ) O(n) O(n)。其中文本串 h a y s t a c k haystack haystack 的长度为 n n n,模式串 n e e d l e needle needle 的长度为 m m m
空间复杂度: O ( 1 ) O(1) O(1)

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        needle_length = len(needle)
        needle_sum = sum(ord(i) for i in needle)
        haystack_sum = sum(ord(i) for i in haystack[:needle_length])
        for i in range(len(haystack) - needle_length + 1):
            if i != 0:
                haystack_sum = haystack_sum - ord(haystack[i-1]) + ord(haystack[i+needle_length-1])
            if needle_sum == haystack_sum:
                for x, y in zip(haystack[i:i+needle_length], needle):
                    if x != y:
                        break 
                else:
                    return i
        return -1

解法三、BM算法:没有采用内存优化重复计算

思路:
h a y s t a c k haystack haystack T T T n e e d l e p needlep needlep p p p,对于给定文本串 T T T 与模式串 p p p,先对模式串 p p p 进行预处理。然后在匹配的过程中,当发现文本串 T T T 的某个字符与模式串 p p p 不匹配的时候,根据启发策略,能够直接尽可能地跳过一些无法匹配的情况,将模式串多向后滑动几位。

B M BM BM 算法具体步骤如下:

  1. 计算出文本串 T T T 的长度为 n n n,模式串 p p p 的长度为 m m m
  2. 设置左指针为 l e f t left left,两个文本串长度差为 d i f f e r differ differ d i f f e r differ differ同时为 l e f t left left 最大移动步长,如果 l e f t < = d i f f e r left<=differ left<=differ,则进入循环体,采用 B M BM BM 算法更新 l e f t left left,步骤如下:
    • 如果文本串对应位置 T [ i + j ] T[i + j] T[i+j] 上的字符与 p [ j ] p[j] p[j] 相同,则继续比较前一位字符。
      1. 如果模式串全部匹配完毕,则返回 T r u e True True
    • 如果文本串对应位置 T [ i + j ] T[i + j] T[i+j] 上的字符与 p [ j ] p[j] p[j] 不相同,则:
      1. 根据坏字符位置表计算出在「坏字符规则」下的移动距离 b a d _ c h a r a c t e r s _ m o v e bad\_characters\_move bad_characters_move
      2. 根据好后缀规则后移位数表计算出在「好后缀规则」下的移动距离 g o o d _ s u f f i x _ m o v e good\_suffix\_move good_suffix_move
      3. 返回两种移动距离的最大值,即 m a x ( b a d _ c h a r a c t e r s _ m o v e , g o o d _ s u f f i x _ m o v e ) max(bad\_characters\_move, good\_suffix\_move) max(bad_characters_movegood_suffix_move)
  3. 如果移动到末尾也没有找到匹配情况,则返回 -1。如果匹配到了,则返回 l e f t left left

时间复杂度: O ( n / m ) O(n/m) O(n/m),最坏 O ( m ∗ n ) O(m*n) O(mn)
空间复杂度: O ( s u f f i x ) O(suffix) O(suffix) s u f f i x suffix suffix 为后缀长度,小于模式串 p p p

class Solution:
    def bm(self, str1, str2, str2_length):
        for i in range(str2_length-1, -1, -1):
            if str1[i] != str2[i]:
                # 坏字符
                bad_char_skewing = i + 1
                for j in range(i-1, -1, -1):
                    if str2[j] == str1[i]:
                        bad_char_skewing = i - j
                        break
                # 好后缀
                suffix = str1[i+1:]
                suffix_length = len(suffix)
                if suffix:
                    good_suffix_skewing = 0
                    for j in range(str2_length-1, -suffix_length, -1):
                        if str2[j-suffix_length:j] == suffix:
                            bad_char_skewing = str2_length - j
                            break
                    return max(bad_char_skewing, good_suffix_skewing)
                return bad_char_skewing
        return True

    def strStr(self, haystack: str, needle: str) -> int:
        haystack_length = len(haystack)
        needle_length = len(needle)
        difference_length = haystack_length - needle_length
        left = 0
        while left <= difference_length:
            skewing = self.bm(haystack[left: left+needle_length], needle, needle_length)
            if skewing is True:
                return left
            left += skewing
        return -1

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏秃然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值