【leetcode刷刷】28. 实现 strStr()、459.重复的子字符串、字符串+双指针总结

28. 实现strStr()

  1. KMP算法,原来是这个,之前上数据结构课的时候应该是学过的,但是早就忘了,现在虽然有点印象,但细节早就不记得了。跟着视频捋了一遍还是很懵。
  2. 印象中的next表计算是右移的那个表,也就是不需要判断j>0那一步,但是现在感觉直接用原始前缀表比较好理解。
  3. 需要注意回退的时候用while,且需要判断j>0。
  4. 时间复杂度O(m+n),空间复杂度O(m)–>next表
  5. 计算next表也可以看成是一个前后缀的匹配,因此回退的时候也使用next[j-1]。但是具体逻辑还没有很清楚。
  • 放几个b站视频下面的解答:[1, i]是后缀,是因为后缀不包括首字母,i是后缀末尾。[0, j]是前缀,j是前缀末尾。因此就是一个前缀和后缀的匹配。同时j也是已经匹配的字符串长度。每次如果想等的话,i和j都会后移一位。
    在这里插入图片描述
    【leetcode刷刷】28. 实现 strStr()、459.重复的子字符串、字符串+双指针总结_第1张图片
class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        # KMP算法
        def get_next(needle):
            next = [0] * len(needle)
            j = 0
            for i in range(1, len(needle)):
                while(j > 0 and needle[i] != needle[j]):
                    j = next[j-1]

                if needle[i] == needle[j]:
                    j+= 1
                next[i] = j
            return next

        next = get_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
                
class Solution(object):
    def strStr(self, haystack, needle):
        """
        :type haystack: str
        :type needle: str
        :rtype: int
        """
        m, n = len(haystack), len(needle)
        for i in range(m):
            if haystack[i:i+n] == needle:  # 不怕越界的
                return i
        return -1 

一句话python

return haystack.find(needle)

459. 重复的子字符串

  1. 并没有搞懂为什么s+s中出现另一个s是循环的必要充分条件。必要条件明白,充分条件是为什么。大概写了一下,可以等价为如果s=a+b=b+a,那么一定是循环,但是怎么严谨证明呢?反证法有没有可能。
  2. 感觉下一次刷肯定会忘掉啊啊啊
class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        ss = s[1:] + s[:-1]  # 掐头去尾
        # 用KMP在ss中匹配s
        KMP_next = self.get_next(s)
        j = 0
        for i in range(len(ss)):
            while j > 0 and ss[i] != s[j]:
                j = KMP_next[j-1]
            if ss[i] == s[j]:
                j += 1
            if j == len(s):
                return True
        return False

    def get_next(self, s):
        j = 0
        KMP_next = [0] * len(s)
        for i in range(1, len(s)):
            while(j > 0 and s[i] != s[j]):
                j = KMP_next[j-1]
            if s[i] == s[j]:
                j += 1
            KMP_next[i] = j
        return KMP_next

总结

  1. 反转字符串,本身使用双指针来实现本地反转:指针可以考虑从前往后还是从后往前
  2. 字符串替代
  3. KMP:字符串匹配/重复子字符串
  4. 双指针的一些使用场景:
  • 数组移除元素,一个指针遍历一个指针修改,来实现本地修改的时间复杂度O(1),而不是移除一个后面的都移动的O(n)
  • 字符串:反转字符串、字符串填充替代、字符串删除空格
  • 链表:反转链表、快慢指针(判断环,很难想啊,只能熟能生巧了)、找环的入口(相遇后再把一个指针放回开头,然后一个速度移动)
  • 两数之和(哈希)、三数之和/四数之和(排序后+双指针)

你可能感兴趣的:(leetcode,python,算法)