leetcode 28. 实现 strStr()

28. 实现 strStr()
实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

示例 1:

输入: haystack = “hello”, needle = “ll”
输出: 2
示例 2:

输入: haystack = “aaaaa”, needle = “bba”
输出: -1
说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。


本方法就是最原始的从头开始匹配,如果匹配错误则接着下一个点继续匹配。综合看来不是很好。

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        hay_count = len(haystack)
        p_count = len(needle)
        if p_count == 0:
            return 0
        i,j = 0,0
        while i < hay_count:
            if haystack[i] == needle[j]:
                j += 1
                i += 1
            else:
                i -= (j-1)
                j = 0
            if j == p_count:
                return i-j
        return -1

相似的查找算法有 KMP,BM,Horspool,之后有空在学一下这几种方法。


看了两天KMP算法,不得不说这个算法真的挺巧妙的。首先看下源码

def KMP_algorithm(string, substring):
    '''
    KMP字符串匹配的主函数
    若存在字串返回字串在字符串中开始的位置下标,或者返回-1
    '''
    pnext = gen_pnext(substring)
    n = len(string)
    m = len(substring)
    i, j = 0, 0
    while (i<n) and (j<m):
        if (string[i]==substring[j]):#字符相匹配,两个游标都后移
            i += 1
            j += 1
        elif (j!=0): 
            j = pnext[j-1]
        else:
            i += 1
    if (j == m):#这里的如果匹配完毕,就返回匹配的首地址
        return i-j
    else:
        return -1
            
    
def gen_pnext(substring):
    """
    构造临时数组pnext
    """
    index, m = 0, len(substring)
    pnext = [0]*m #创建一个等长的0列表
    i = 1
    while i < m:
        if (substring[i] == substring[index]):#字符相匹配,两个游标都后移
            pnext[i] = index + 1 #pnext[i] 中保存位置i之前最大的匹配个数
            index += 1
            i += 1
        elif (index!=0):#如果不匹配,则回溯游标,回溯到前一个index在pnext中的位置
            index = pnext[index-1]
        else:
            pnext[i] = 0#这种情况即index == 0,并且两者还不匹配
            i += 1#直接去匹配下一个
    return pnext
 
if __name__ == "__main__":
    string = 'abcxabcdabcdabcy'
    substring = 'abcdabcy'
    out = KMP_algorithm(string, substring)
    print(out)

算法有点难理解 ~_~
i 为原始的列表中的游标
index 为子模板的列表中的游标
pnext[ i ] 为第 i 位和之前的字串中 匹配成功的前缀和后缀的长度
首先分为三种情况:

  1. s[ index ] == s[ i ]: 表示子模板中的元数与原始列表中的元素匹配上了。这个时候在 pnext[i] = index + 1,保存第i个和其之前最长的匹配前后缀个数。
  2. 匹配不上,并且index不等于0,这意味着,在这之前是有匹配成功的,就是在这里可能会断掉。这时候就需要回溯index到一个适合的位置。这个位置的确定有点迷。首先例如: abbabbabbac,我们对齐创建pnext数组开始的匹配比较清楚 pnext = [0001234567*],在最后一位的时候 index = 7, i = 10,两者不匹配。此时的 pnext 列表内的值如下
    在这里插入图片描述
    代码里面是回溯的 index = pnext [ index - 1 ],即 pnext[6] = 4,index = 4,向前移动了三位,也就是匹配前重复的数组长度3,list内有3个0, 如果匹配的长度超过3,那么 s[i]之后的值是和s[3]会重复的。因为只有重复匹配的长度才会超过3,所以这个地方回溯的移动值就是列表前面重复的长度。
  3. 第三种情况就是index = 0, 但是 s[index] != s[ i ], 表示两个串的串首都不相等,后移 i 。

上述就是pnext列表的生成,有点不好理解,目前我自己也没有完全理解,惭愧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值