题一:344. 反转字符串(easy)
链接
视频总结
本题非常简单,唯一需要注意的是库函数的使用时机,只要不是题目的关键步骤,且库函数已经知道如何实现,那么还是可以使用的
编程思路
Me:
- 双指针,一个0一个len减一
while l<r 等于时不操作,互换
卡尔:
注意尝试while和for的写法
力扣实战
思路一:
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
# for 循环的写法,和while循环的写法的思路如出一辙
l = 0
r = len(s)-1
for i in range(len(s)):
if i < r:
s[i],s[r] = s[r],s[i]
r -= 1
else:
break
return s
题二: 541. 反转字符串II
链接
视频总结
关键点
编程思路
Me:
- 1.写一个反转字符串的函数
2.获取字符串长度,根据要求截取字符串,然后过定义函数
3.拼接几个部分
疑问:最后剩余的>2k怎么办
卡尔:
1.for循环的自加很多人默认为i+=1,此处+=2k会比较好。即操作数组或者字符串是一段一段的处理时,i可以一段段跳,而不是只加一。
2.定义reverse函数,要么传入完整字符串,那么就要讨论情况,然后截取,然后反转。或者在定义reverse函数时也输入反转的起点和终点
力扣实战
思路一:
class Solution:
def reverseStr(self, s: str, k: int) -> str:
l = len(s)
i = 0
s=list(s)
def reverse1(m,n,s): # 翻转字符串s的i到j段.其中m和n是索引
while m < n:
s[m],s[n]=s[n],s[m]
m += 1
n -= 1
return s
while i<l:
if l-i>2*k: # 长度大于2k,此处不可等于,等于时翻转后就得输出了
s = reverse1(i,i+k-1,s)
i += 2*k
elif k<=l-i<=2*k: # 大于等于k小于2k
s = reverse1(i,i+k-1,s)
return ''.join(s) # 若写成s,则结果为["c","b","a","d","e","f","g"],
else:
s = reverse1(i,l-1,s)
return ''.join(s) #若写str(s)结果是"['c', 'b', 'a', 'd', 'e', 'f', 'g']",也就是我们需要把["c","b","a","d","e","f","g"]转为"cbadefg"
# 反思1:
思路二:
#官方解答,第二段无需讨论,非常精彩,其次for的每次步进非1的方法也可以学习!
class Solution:
def reverseStr(self, s: str, k: int) -> str:
t = list(s)
for i in range(0, len(t), 2 * k):
t[i: i + k] = reversed(t[i: i + k])
return "".join(t) # join方法指把t里的对象以""里的东西分隔在组成一个字符串,此处双引号里啥也没有
文档总结
1.
题三:剑指Offer 05.替换空格
链接
视频总结
关键点
编程思路
Me:
1.一层for循环,遇到空格时换(换了之后索引会变,所以思路错误)
卡尔:
- 字符串扩充0,空格替换后的长度来算0的个数
- 从后往前,(而不是从前往后,从前往后后面的元素都要移动),一个指针在老数组末尾,一个在新的末尾
力扣实战
思路一:
class Solution:
def replaceSpace(self, s: str) -> str:
#思路:一次遍历获得空格数k;在结尾补充2k个0(加上前面的k个正好3k个,)双指针
##i指向老字符串的末尾,j指向新字符串的末尾,从后向前遍历;当i处不为空格时移到末尾;等于空格时末尾覆盖
#三个字符。
count=0
m = len(s)-1
for i in s: # 获得空格数,错因:‘’里面没有写空格‘ ’
if i == ' ':
count+=1
s = s+'00'*count
l = len(s)-1
s = list(s)
while m>-1:
if s[m] !=' ':
s[l]=s[m]
l-=1
else:
s[l-2:l+1]=['%','2','0']
l-=3
m-=1
return ''.join(s)
# 反思1:
思路二:
#另一种写法,部分库函数不一样
class Solution:
def replaceSpace(self, s: str) -> str:
counter = s.count(' ')
res = list(s)
# 每碰到一个空格就多拓展两个格子,1 + 2 = 3个位置存’%20‘
res.extend([' '] * counter * 2)
# 原始字符串的末尾,拓展后的末尾
left, right = len(s) - 1, len(res) - 1
while left >= 0:
if res[left] != ' ':
res[right] = res[left]
right -= 1
else:
# [right - 2, right), 左闭右开 这里很重要!!左闭右开!!
res[right - 2: right + 1] = '%20' # 也可以是一个列表,里面的三个元素是字符串,可debug观看。观看后可知两种操作都合法
right -= 3
left -= 1
return ''.join(res)
文档总结
1. 其实很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
这么做有两个好处:1.不用申请新数组。2.从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。时间复杂度,空间复杂度均超过100%的用户。
2.在cpp中字符串和数组是有区别的,虽然字符串可以视为字符数组;应该继续研究一下python中的字符串和数组的区别
题四:151.翻转字符串里的单词
链接
视频总结
关键点
编程思路
Me:无思路
卡尔:
删空格:双指针,快指针遍历字符串,找到我们需要移动的对象(非空格),慢指针指向待移动的位置,初始为0,而且还要在每个单词之间留下一个空格,最后一步我没想到
然后把整体翻转,再以空格为界来翻转。
力扣实战
思路一:
class Solution:
def reverseWords(self, s: str) -> str:
def trim_space(s): #删去空格
left = 0
right = len(s)-1
while left<right and s[left] ==' ':
left += 1
while left<right and s[right] == ' ':
right -= 1
l = r = left
out =[]
while l <=right:
if s[l] != ' ': # if elif else同时出现和if if if 同时出现的逻辑不一样,前者三个子语句只会执行一条,后者满足调节就都会执行
out.append(s[l])
elif out[-1] != ' ': #执行到这里则说明if没执行,也就是s[l]此时为空,那么此时判断out里最后一个是不是空,如果不是则说明前一个单词到了末尾,可以把当前l处的空格放进out作为单词间的分割空格,若遇到了连续的空格,过判断语句发现out末尾是空格,则跳过,也就避免了单词中间的连续的空格
out.append(s[l])
l += 1
return out
tem = trim_space(s)
tem.reverse()
i = j = 0
while i<len(tem):
if tem[i] == ' ': #找到第一个空格,然后对这一段单词翻转
tem[j:i]=list(reversed(tem[j:i])) # 此处写成tem[j:i].reverse()就错误,这不是部分翻转的代码,这样写数组保持不变
j = i+1
elif i == len(tem)-1: # 必须考虑走到末尾的情况,否则最后一个单词不会翻转
tem[j:i+1]=list(reversed(tem[j:i+1])) # reversed返回的是一个容器,故需要转成列表
i+=1
return ''.join(tem)
# 反思1:
题五: 剑指Offer58-II.左旋转字符串
链接
视频总结
力扣实战
思路一:
# s长度×2,然后截取一部分,时间上最短
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
l=len(s)
s = s+s
tem = list(s)
return ''.join(tem[n:n+l])
# 随想录文档更牛皮
# 方法一:可以使用切片方法
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[n:] + s[0:n]
思路二:
# 先翻转前n,再翻转n后,再翻转全部
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
# 注意这九行的写法,参照了上一题改了无数次。这一思路随想录上的写法和我的写法一模一样,说明字符串转成列表在操作确实没走弯路,也说明了字符串的自由度没有列表那么高
l=len(s) # 获取长度
s=list(s) # 字符串转为列表以便于数组翻转操作
s[0:n] = list(reversed(s[0:n])) # 翻转前n个和n以后的
s[n:] = list(reversed(s[n:]))
s.reverse() #整体翻转
return ''.join(s) #把s里每个个体以‘’里的东西分隔开
思路三:
# 方法三:如果连reversed也不让使用,那么自己手写一个
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
def reverse_sub(lst, left, right):
while left < right:
lst[left], lst[right] = lst[right], lst[left]
left += 1
right -= 1
res = list(s)
end = len(res) - 1
reverse_sub(res, 0, n - 1)
reverse_sub(res, n, end)
reverse_sub(res, 0, end)
return ''.join(res)
# 同方法二
# 时间复杂度:O(n)
# 空间复杂度:O(n),python的string为不可变,需要开辟同样大小的list空间来修改
思路四:
#方法四:考虑不能用切片的情况下,利用模+下标实现
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
new_s = ''
for i in range(len(s)):
j = (i+n)%len(s)
new_s = new_s + s[j]
return new_s
文档总结
1. 文档给了三个不错的写法