代码随想录算法训练营第九天 | Python | LeetCode151.反转字符串中的单词、卡码网55.右旋字符串、LeetCode28.实现strStr()、LeetCode459.重复的子字符串

LeetCode 151. 反转字符串中的单词

题目:https://leetcode.cn/problems/reverse-words-in-a-string/description/
解析:https://programmercarl.com/0151.%E7%BF%BB%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%87%8C%E7%9A%84%E5%8D%95%E8%AF%8D.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

字符串的问题用python解决起来很快,因为有很多内嵌函数可以用。

  1. strip()可以去除前后空格
  2. split()既可以去除前后空格,又可以去除中间多余空格

反转:

  1. 字符串经过split变为list,反转list用双指针就可以完成
  2. 直接反转字符串,再反转每个单词字符串,反转字符串用[::-1]可以完成

反转list:

class Solution:
    def reverseWords(self, s: str) -> str:
        s = s.split()
        left = 0
        right = len(s) - 1
        while left < right:
            s[left], s[right] = s[right], s[left]
            left += 1
            right -= 1
        return ' '.join(s)

反转字符串:

class Solution:
    def reverseWords(self, s: str) -> str:
        s = s.strip()[::-1].split()
        return ' '.join([c[::-1] for c in s])

卡码网 55. 右旋字符串

题目:https://kamacoder.com/problempage.php?pid=1065
链接:https://programmercarl.com/kama55.%E5%8F%B3%E6%97%8B%E5%AD%97%E7%AC%A6%E4%B8%B2.html#%E6%80%9D%E8%B7%AF

一看到这题就知道,进阶版必然是要求不额外申请空间。

但是我不会)一开始想着用快慢指针,把快指针的值覆盖给慢指针。但无论是从前往后覆盖,还是从后往前覆盖,都会导致数据丢失。所以小小的申请了一下额外空间……

import sys

input_data = sys.stdin.read().strip().splitlines()
n = int(input_data[0])
s = list(input_data[1])

n_list = s[len(s)-n::]
right = len(s) - 1

for left_char in s[len(s)-n-1::-1]:
    s[right] = left_char
    right -= 1
    
s[:n] = n_list
print(''.join(s))

中间实践的时候出错了,把for left_char in s[len(s)-n-1::-1]写成了for left_char in s[len(s)-n-1:-1:-1],中间的这个-1是指倒数第一个数(我以为是截止到第一个数)。

如果不申请额外空间应该怎么做呢?用反转做。

先切片反转,再整体反转

import sys

input_data = sys.stdin.read().strip().splitlines()
n = int(input_data[0])
s = str(input_data[1])

s = s[:-n][::-1] + s[-n:][::-1]
s = s[::-1]

print(s)

先整体反转,再切片反转

import sys

input_data = sys.stdin.read().strip().splitlines()
n = int(input_data[0])
s = str(input_data[1])

s = s[::-1]
s = s[:n][::-1] + s[n:][::-1]

print(s)

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

题目:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/
链接:https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html

用到了KMP算法【烤馍片】,建议看视频学习。这个算法是完成字符匹配问题(字符连续相同)。

暴力解法是:把目标串的每一个字符当做起点,截取一段字符串,遍历该字符串与模式串是否匹配。这样需要重复遍历目标串很多次。KMP算法的厉害之处在于,只需要遍历目标串一次。

比如:

目标串是 aabaabaaf
模式串是 aabaaf

在遍历目标串时,发现到下标5的字符(b)的时候,和模式串下标5的字符(f)开始出现区别。于是KMP非常聪明的发现,指向模式串的指针只需要 回退到下标2的字符(b)就可以了。

为什么要回退到下标2的字符?因为我们知道目标串下标5的字符(b)前面的字符有aa,模式串下标2的字符(b)前面也有aa,聪明的KMP算法记住我们已经匹配过aa了,不需要重新匹配一遍了。

为什么KMP算法可以记住aa已经匹配过一遍了?因为当我们的模式串指针指向下标5的字符(f)时发现,前5个字符(aabaa)的前后缀是一样的,那我们就没必要再花时间匹配aa了,把指针直接回退到b就可以了。aabaa前后缀相等的数量是2(aa=aa),那我们回退到下标为2的位置(b)。

这里我们设置一个与模式串等长的数组next,专门放:

模式串前 i 个字符前后缀相等的数量。

i前i个字符前后缀相等数量
1a0
2aa1
3aab0
4aaba1
5aabaa2
6aabaaf0

那么next数组为[0,1,0,1,2,0]模式串s[5]=='f', next[5-1]==2,回退到下标2。

怎么通过代码找出next数组呢?这也是字符串匹配问题,保证前缀和后缀匹配。这里的目标串是后缀,模式串是前缀。对目标串(后缀)的处理还是那句话,闷头往前走就行,算法会记住你遍历过什么,对模式串的处理是 要找到他的next数组,有可能会回退。next可以在遍历过程中找到:

在这里插入图片描述
不如直接看代码:

class Solution(object):
    def get_next(self, s):
        j = 0
        next = [0]*len(s)
        for i in range(1, len(s)):
            while s[i] != s[j] and j > 0:
                j = next[j-1]
            if s[i] == s[j]:
                j += 1
            next[i] = j
        return next
    def strStr(self, haystack, needle):
        """
        :type haystack: str
        :type needle: str
        :rtype: int
        """
        if len(haystack) < len(needle):
            return -1
        next = self.get_next(needle)
        j = 0
        for i in range(len(haystack)):
            while needle[j] != haystack[i] and j > 0:
                j = next[j-1]
            if needle[j] == haystack[i]:
                j += 1
            if j == len(needle):
                return i - len(needle) + 1
        return -1      

LeetCode 459. 重复的子字符串

题目:https://leetcode.cn/problems/repeated-substring-pattern/description/
链接:https://programmercarl.com/0459.%E9%87%8D%E5%A4%8D%E7%9A%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

字符串匹配,依旧KMP,找到s的next。

那next怎么用呢?

这里展示几种next:

a b a b a b
0 0 1 2 3 4

a b a b a
0 0 1 2 3

a b a b c a b
0 0 1 2 0 1 2

因为我也不知道怎么处理,直接看了代码反推:

代码里判断了len(s) % (len(s)-next[-1]) == 0,这里的(len(s)-next[-1])指字符串第一个不循环子串。如果len(s) % (len(s)-next[-1]) == 0表示字符串是循环的。

class Solution(object):
    def get_next(self, s):
        next = [0]*len(s)
        j = 0
        for i in range(1, len(s)):
            while s[j] != s[i] and j > 0:
                j = next[j-1]
            if s[j] == s[i]:
                j += 1
            next[i] = j
        return next
    def repeatedSubstringPattern(self, s):
        """
        :type s: str
        :rtype: bool
        """
        next = self.get_next(s)
        if next[-1] != 0 and len(s) % (len(s)-next[-1]) == 0:
            return True
        return False

  • 27
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值