代码随想录算法训练营第十天|28. 找出字符串第一个匹配项的下标,459.重复的子字符串

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

题目链接:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

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

题目思路:KMP算法

逐一匹配文本串和模式串,当有字母不匹配时,回到模式串到上一个字母为止的最长相同前后缀那里。

next数组:第i个entry记录了模式串到第i个字符串为止的字符的最长相同前后缀的个数。

原理:那个位置之后到当前前一个的字符串在上次是匹配成功的,又因为它和那个位置前面的那部分是相同的,所以前面那部分就不用再和文本串匹配了,直接从那个位置匹配就好。

代码实现

KMP思路

class Solution:
    def getNext(self, next, s):
        j = 0
        next[0] = 0
        for i in range(1, len(s)):
            while j > 0 and s[i] != s[j]:
                j = next[j - 1]
            if s[i] == s[j]:
                j += 1
            next[i] = j
        return next
    
    def strStr(self, haystack, needle):
        if len(needle) == 0:
            return 0
        next = [0] * len(needle)
        self.getNext(next, needle)
        j = 0
        for i in range(len(haystack)):
            while j > 0 and haystack[i] != needle[j]:
                j = next[j - 1]
            if haystack[i] == needle[j]:
                j += 1
            if j == len(needle):   # 当匹配成功的个数等于我们想要找的模式串时,
                                   # 说明全部匹配成功
                return i - len(needle) + 1
        return -1
代码和思路详解

我们以字符串“abxabcabxabx"为例,结合代码,具象化next数组的构造(next数组构造的思路也是KMP):

在我们匹配到最后一个字符”x“时,x前面的”abxab"已经都匹配成功,此时i为11,指向“x”,j为5,指向字符串第六个字符“c"。如果x也能匹配成功,它的next数组中对应的值就为5+1=6,但很可惜它不是。那么按照最常规的思路,我们需要从整个字符串的首位”a”重新开始匹配,当发现有等于x的字符时,再看这个字符到第一个的字符串是否和x前面的那些字符串匹配(即:从a开始,到b,再到x,发现这个字符和最后的那个x一样,就看前一个x到字符串首尾a的字符串“abx”是否和到最后一个x为止的后缀相同,发现也有“abx”,那么至少意味着最长相同前后缀大于≥3)。但KMP算法告诉我们不需要从头来过。我们直接看next数组中序号为j-1的值,为2。这个2代表着对于到第j个字符串前一个字符的字符串“abxab”中,序号为2的字符(“x“)是成功匹配的位置,也就是说x的前半部分和后半部分相等。而”x“的后半部分”ab“匹配到最后一个字符“x”之前已经匹配成功了,如果序号为2的这个字符和最后一个字符(即”x“)匹配成功,我们也已经知道x前面的”ab“是匹配成功的,就直接得到next数组的第i个值为2+1 = 3。

KMP一个特色是在遍历haystack字符串时,不会回头,会向前找的只有我们要找的字符串needle。接下来我们假设haystack是“abxabcabxabx”,想要找的needle是“abxabx”。我们知道“abxabx”的next数组为[0 0 0 1 2 3]。

刚开始,我们从haystack和needle的第一个开始匹配,前五个都是成功的 此时i和j都为4,到第六个字符串时,发现c和x不匹配。这时看next数组的第四个序数的值,为2,所以我们直接把next数组序数为2的值,x和haystack当前遍历到的值c做匹配,(如果匹配,那么i+1变为6,这时i的值和needle的长度相同,说明我们成功匹配好了,返回结果),发现不匹配,那么就继续找next数组叙述为j-1=1的值,发现为0,说明j变为0,我们从needle首位重新匹配。 

Python 自带方法

python提供了string.index(s_string)string.find(s_string)方法,都可以帮助我们找到子字符串s_string在字符串string中第一次出现的位置,不同的是如果子字符串不存在,Index函数会抛出ValueError异常,而find函数则会返回-1。

class Solution:
    def strStr(self, haystack, needle):
        try:
            return haystack.index(needle)

        except ValueError:
            return -1
class Solution:
    def strStr(self, haystack, needle):
        return haystack.find(needle)

459.重复的子字符串

题目链接:459. 重复的子字符串 - 力扣(LeetCode)

题目大意:给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

题目思路:当一个字符串s有重复的子字符串,那么它肯定前面一部分和后面一部分相同,那么既然前面有相同的子串,后面有相同的子串,用 s + s,这样组成的字符串中,后面的子串做前串,前面的子串做后串,就一定还能组成一个s.

class Solution(object):
    def repeatedSubstringPattern(self, s):
        ss = s[1:] + s[:-1]
        return ss.find(s) != -1
        

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的数组,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值