代码随想录算法训练营|Day 9

Day 9

今日任务

● 151.翻转字符串里的单词

● 卡码网:55.右旋转字符串

● 28. 实现 strStr()

● 459.重复的子字符串

● 字符串总结

● 双指针回顾

详细布置

151.翻转字符串里的单词

建议:这道题目基本把 刚刚做过的字符串操作 都覆盖了,不过就算知道解题思路,本题代码并不容易写,要多练一练。

题目链接/文章讲解/视频讲解:https://programmercarl.com/0151.翻转字符串里的单词.html

class Solution:
    def reverse_word(self, s:list, start:int,end:int):
        while start < end:
            s[start],s[end] = s[end],s[start]
            start += 1
            end -= 1

    def reverseWords(self, s: str) -> str:
        #step1 remove extra space to get a new string
        res = ""
        fast = 0
        s = list(s)
        s.reverse()
        while fast < len(s):
            if s[fast] != " ":
                if len(res) != 0:
                    res += " "
                while fast < len(s) and s[fast] != " ":
                    res += s[fast]
                    fast += 1
            else:
                fast += 1
        #step2 reverse words
        res = list(res)
        p1,p2=0,0
        while p2 <= len(res):
            if p2 == len(res) or res[p2] == " ":
                self.reverse_word(res,p1,p2-1)
                p1 = p2+1
                p2 +=1
            else:
                p2+=1
        return "".join(res)

卡码网:55.右旋转字符串

建议:题解中的解法如果没接触过的话,应该会想不到

题目链接/文章讲解:

右旋转

知识:先改变段顺序,再改变字符顺序

num_seg = int(input())
s = input()
s = s[::-1]
s = s[:num_seg][::-1] + s[num_seg:][::-1]
print(s)
#获取输入的数字k和字符串
k = int(input())
s = input()

#通过切片反转第一段和第二段字符串
#注意:python中字符串是不可变的,所以也需要额外空间
s = s[len(s)-k:] + s[:len(s)-k]
print(s)

28. 实现 strStr() (本题可以跳过)

因为KMP算法很难,大家别奢求 一次就把kmp全理解了,大家刚学KMP一定会有各种各样的疑问,先留着,别期望立刻啃明白,第一遍了解大概思路,二刷的时候,再看KMP会 好懂很多。

或者说大家可以放弃一刷可以不看KMP,今天来回顾一下之前的算法题目就可以。

因为大家 算法能力还没到,细扣 很难的算法,会把自己绕进去,就算别人给解释,只会激发出更多的问题和疑惑。所以大家先了解大体过程,知道这么回事, 等自己有 算法基础和思维了,在看多看几遍视频,慢慢就理解了。

题目链接/文章讲解/视频讲解:https://programmercarl.com/0028.实现strStr.html

kmp_1
kmp_2
kmp_3

failureFunction(P):             # 输入:模式串 P,长度 m
  F[0] = 0                      # F[0] 永远是 0,因为单字符没有真前后缀(proper prefix/suffix)
  j = 1, len = 0                # j 用来扫描下标 1…m-1,len 记录“当前最长前后缀长度”(matched length)

  while j < m do                # 对 P[1..m-1] 逐个位置填 F[j]
    if P[j] == P[len] then      # 情况 A:当前位置能在更长的前后缀上继续匹配
      len = len + 1             # “匹配长度”加 1
      F[j] = len                # 在 j 位置能匹配的最大前后缀长度
      j = j + 1                 # 继续下一个字符
    else if len > 0 then        # 情况 B:失配,但已有非零的前后缀可回退
      len = F[len - 1]          # 回到上次“可能”的前后缀长度,重用已计算结果(跳过回退 j)
    else                        # 情况 C:失配且 len==0,无任何前后缀可用
      F[j] = 0                  # 说明 P[0..j] 没有非空的真前后缀
      j = j + 1                 # 向右继续
    end if
  end while

  return F                      # 返回长度为 m 的 failure (LPS) 数组

class Solution:
    def getNext(self, next: List[int], s: str) -> None:
        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
    
    def strStr(self, haystack: str, needle: str) -> int:
        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

理解错误写出的代码:

class Solution:
    def getNext(self, s: str, next:List[int]):
        next[0] = 0
        j = 0
        for i in range(1, len(s)):
            if s[j] == s[i]:
                j += 1
            while j > 0 and s[j] != s[i]:
                j = next[j-1]
            next[i] = j
            

    def strStr(self, haystack: str, needle: str) -> int:
        if len(needle) == 0:
            return 0
        next = [0] * len(needle)
        self.getNext(needle, next)
        j = 0
        for i in range(len(haystack)):
            if haystack[i] == needle[j]:
                if j == len(needle)-1:
                    return i-j
                j+=1
            else:
                if j > 0:
                    j = next[j-1]
        return -1
            
        

459.重复的子字符串 (本题可以跳过)

本题算是KMP算法的一个应用,不过 对KMP了解不够熟练的话,理解本题就难很多。

我的建议是 KMP和本题,一刷的时候 ,可以适当放过,了解怎么回事就行,二刷的时候再来硬啃

题目链接/文章讲解/视频讲解:https://programmercarl.com/0459.重复的子字符串.html

class Solution:
    def getNext(self, s:str, next:List[int]):
        next[0] = 0
        j = 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 
    def repeatedSubstringPattern(self, s: str) -> bool:
        if len(s) == 0:
            return False
        next = [0]* len(s)
        self.getNext(s,next)
        #next[-1]:最长相等前后缀的长度
        #len(s) - next[-1]:不属于这个最长前后缀的部分/最长相等前后缀不包含的子串的长度
        #如果len % (len - (next[len - 1] + 1)) == 0 
        #则说明数组的长度正好可以被 最长相等前后缀不包含的子串的长度整除
        #说明该字符串有重复的子字符串
        if next[-1] != 0 and len(s) % (len(s) - next[-1]) == 0:
            return True
        return False

        
        

字符串总结

比较简单,大家读一遍就行

题目链接/文章讲解:https://programmercarl.com/字符串总结.html

双指针回顾

此时我们已经做过10道双指针的题目了,来一起回顾一下,大家自己也总结一下双指针的心得

文章讲解:https://programmercarl.com/双指针总结.html

posted @ 2025-06-29 18:52  ForeverEver333  阅读(26)  评论(0)    收藏  举报