代码随想录算法训练营第九天(补)|28. 实现 strStr()、459. 重复的子字符串

82 阅读2分钟

28. 实现 strStr()

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

题目链接:leetcode.cn/problems/fi…

解题思路:

  1. KMP算法的作用是在一个串中查找是否出现过另一个串。主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。
  2. 先写获取前缀数组next的函数。前缀数组是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。接着使用kmp算法。

代码:

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        def getNext(s):
            n = len(s)
            s_next = [0] * n
            i = 0
            j = 1

            while j < n:
                if s[j] == s[i]:
                    i += 1
                    s_next[j] = i
                    j += 1
                else:
                    if i == 0:
                        s_next[j] == 0
                        j += 1
                    else:
                        i = s_next[i - 1]
            return s_next
        
        s_next = getNext(needle)
        h_len = len(haystack)
        n_len = len(needle)
        i = 0
        j = 0
        while i < h_len:
            if haystack[i] == needle[j]:
                i += 1
                j += 1
            else:
                if j == 0:
                    i += 1
                else:
                    j = s_next[j - 1]
        
            if j == n_len:
                return i - j
        
        return -1
        

459. 重复的子字符串

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

题目链接:leetcode.cn/problems/re…

解题思路:

  1. 简单做法是:将两个 s s 连在一起,并移除第一个和最后一个字符,如果得到的字符串包含 s,那么符合题目要求。
  2. KMP算法:使用next数组,假设字符串s使用多个重复子串构成(这个子串是最小重复单位),重复出现的子字符串长度是x,所以s是由n * x组成。因为字符串s的最长相同前后缀的长度一定是不包含s本身,所以 最长相同前后缀长度必然是m * x,而且 n - m = 1。所以如果 nx % (n - m)x = 0,就可以判定有重复出现的子字符串。

代码:

class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        def getNext(s):
            n = len(s)
            i = 0
            j = 1
            s_next = [0] * n

            while j < n:
                if s[j] == s[i]:
                    i += 1
                    s_next[j] = i
                    j += 1
                else:
                    if i == 0:
                        s_next[j] = 0
                        j += 1
                    else:
                        i = s_next[i - 1]
            
            return s_next
        
        n = len(s)
        s_next = getNext(s)
        if s_next[-1] != 0 and n % (n - s_next[-1]) == 0:
            return True
        else:
            return False