一、151.翻转字符串里的单词
建议:这道题目基本把 刚刚做过的字符串操作 都覆盖了,不过就算知道解题思路,本题代码并不容易写,要多练一练。题目链接/文章讲解/视频讲解:代码随想录
1. 看完代码随想录的想法
法1:定义翻转函数+另开新数组+剔除空格+双指针翻转单词
总体思路:注意翻转单词和翻转字符并不一样,此处还需要剔除多余空格,保留两两单词之间的唯一空格。首先,可以将整个字符串全部反转一次,然后再将各个单词的字符串进行翻转;其次,使用双指针法进行空格剔除,快指针用于遍历整个字符串,慢指针用于存放不等于空格的字符,并且需要在每个单词之间增加一个空格。
(1)首先定义一个函数single_reverse,用于给定一个字符串以及指定的头和尾,将这个字符串的指定位置进行翻转;
(2)接下来定义主函数:首先另开一个新字符串,用于存放最终结果;定义一个指针初始化指向索引为0处;然后使用list()将给定的字符串强制转化为列表形式,方便进行遍历取值;最后使用reverse库函数将这个字符串列表进行整体全部翻转;
(3)接下来删除多余空格:首先指针遍历整个字符串列表(while fast < len(s):),如果该位置不是空格则进入下一步,如果是空格则指针继续指向下一个位置,直到该位置不是空格;如果该位置不是空格,我们需要添加一个判断,如果这个单词是结果集的第一个单词,那么不需要添加空格,因为第一个单词前面不需要空格;接下来我们需要将这个非空格位置对应的值存放进结果集result中,并且继续向下遍历,直到一个单词全部写入结果集;进入下一个循环后结果集里会添加一个空格,这样就满足了每个单词之间只有一个空格;
(4)最后我们需要调用最开始定义的翻转指定位置的字符串,对每个单词进行翻转;初始化快慢指针均指向0;然后将结果集字符串转化为列表;同样的以空格为界,快指针去遍历整个结果集字符串,遇到空格就判断前为同一单词的字符,并调用函数将其翻转;下一次循环需要将慢指针指向快指针+1处,快指针向后移动一位即可;
(5)最后之间拼接反转后的单词。
class Solution:
def single_reverse(self, s, 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:
result = ""
fast = 0
# 1. 首先将原字符串反转并且除掉空格, 并且加入到新的字符串当中
# 由于Python字符串的不可变性,因此只能转换为列表进行处理
s = list(s)
s.reverse()
while fast < len(s):
if s[fast] != " ":
if len(result) != 0:
result += " "
while s[fast] != " " and fast < len(s):
result += s[fast]
fast += 1
else:
fast += 1
# 2.其次将每个单词进行翻转操作
slow = 0
fast = 0
result = list(result)
while fast <= len(result):
if fast == len(result) or result[fast] == " ":
self.single_reverse(result, slow, fast - 1)
slow = fast + 1
fast += 1
else:
fast += 1
return "".join(result)
双指针法:
(1)首先使用split函数将字符串拆分成字符串列表,默认为按空格进行拆分;
(2)定义左指针和右指针,分别指向每个字符串列表的头和尾,并将每个单词进行翻转;
(3)最后返回用join函数以空格“ ”进行连接。
class Solution:
def reverseWords(self, s: str) -> str:
words = s.split()
left = 0
right = len(words) - 1
while left < right:
mid = words[left]
words[left] = words[right]
words[right] = mid
left += 1
right -= 1
return " ".join(words)
2、遇到的困难及解决
(1)需要特别注意:空格" "引号里面需要空格,而不是习惯性直接写引号!
(2)split()函数:split函数传入的是字符串,输出的是字符串列表。
二、卡码网:55.右旋转字符串
建议:题解中的解法如果没接触过的话,应该会想不到题目链接/文章讲解: 右旋转
1. 看到本题的第一想法
首先使用list函数将字符串转化为字符串列表;然后如果想将倒数第n个元素移动到整个数组的最前面,那么不可避免每次挪动一个元素,都需要使用循环遍历将前面的元素依次向后移动,实现起来非常困难。
2. 看完代码随想录的想法
首先对字符串数组进行切片,然后再进行拼接。
s=int(input())
k=input()
s=s[len(s)-k:] + s[:len(s)-k]
print(s)
三、28. 实现 strStr()
因为KMP算法很难,大家别奢求 一次就把kmp全理解了,大家刚学KMP一定会有各种各样的疑问,先留着,别期望立刻啃明白,第一遍了解大概思路,二刷的时候,再看KMP会 好懂很多。或者说大家可以放弃一刷可以不看KMP,今天来回顾一下之前的算法题目就可以。
因为大家 算法能力还没到,细扣 很难的算法,会把自己绕进去,就算别人给解释,只会激发出更多的问题和疑惑。所以大家先了解大体过程,知道这么回事, 等自己有 算法基础和思维了,在看多看几遍视频,慢慢就理解了。
题目链接/文章讲解/视频讲解:代码随想录
本题是KMP 经典题目。以下文字如果看不进去,可以看《代码随想录》算法视频公开课 (opens new window),相信结合视频再看本篇题解,更有助于大家对本题的理解。
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
return haystack.find(needle)
四、459.重复的子字符串
本题算是KMP算法的一个应用,不过 对KMP了解不够熟练的话,理解本题就难很多。
我的建议是 KMP和本题,一刷的时候 ,可以适当放过,了解怎么回事就行,二刷的时候再来硬啃
题目链接/文章讲解/视频讲解:代码随想录
1. 看完代码随想录的想法
(1)判断输入的字符串长度是否合法,要求非空并且有子串,所以长度必须大于1,否则直接返回False;
(2)接下来将两个字符串分别去掉头和尾并将它们拼接,如果使用find函数还能在拼接后的字符串找到原始字符串的话,就说明原字符串可以由它的子串反复构成;
(3)最后返回bool类型的结果,如果可以就返回True,否则返回False。
class Solution:
def repeatedSubstringPattern(self, s:str) -> bool:
if len(s) <= 1:
return False
ss = s[1:]+s[:-1]
return ss.find(s)!=-1
2. 实现过程中遇到的困难及解决
(1)在定义函数时注意->表示最后返回的结果类型。
(2)find()函数:
五、字符串总结
题目链接/文章讲解: 代码随想录
1. 字符串定义
字符串就是由多个字符组成的有限序列,也可以理解为字符数组。
2. 是否应该使用库函数
例如substr,split,reverse之类的库函数,如果题目关键的部分直接用库函数就可以解决,建议不要使用库函数;如果库函数仅仅是 解题过程中的一小部分,并且你已经很清楚这个库函数的内部实现原理的话,可以考虑使用库函数。
并且如果调用库函数,需要了解其实现原理以及时间复杂度。
六、双指针总结
此时我们已经做过10道双指针的题目了,总结一下双指针的心得文章讲解:代码随想录