一、344.反转字符串
建议: 本题是字符串基础题目,就是考察 reverse 函数的实现,同时也明确一下 平时刷题什么时候用 库函数,什么时候 不用库函数题目链接/文章讲解/视频讲解:代码随想录
1. 看到这道题的第一想法
因为题目要求时间复杂度为O(1),不可以另外申请空间,所以直接调用reverse()函数。
已AC的代码如下:
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
return s.reverse()
2. 看完代码随想录的想法
使用双指针法,首先定义左指针和右指针分别指向字符串数组的头和尾;
然后进入循环遍历,将左右指针同时向中间移动,直到两个指针指向同一个字符;
接下来在循环遍历过程中,利用中间变量先存放左指针的元素,然后将右指针值传递给左指针,再将中间变量所存放的原左指针的值传递给右指针,这样就完成了两个元素的交换,每次交换完成后需要将左右指针向中间移动一位;
最后返回交换完毕后的字符串数组。
class Solution:
def reverseString(self, s: List[str]) -> None:
left = 0
right = len(s)-1
while left < right:
mid = s[left]
s[left] = s[right]
s[right]=mid
left += 1
right -= 1
return s
二、541. 反转字符串II
建议:本题又进阶了,自己先去独立做一做,然后在看题解,对代码技巧会有很深的体会。题目链接/文章讲解/视频讲解:代码随想录
1. 看到这道题的第一想法
首先题意理解模糊不清;其次想要使用双指针法来实现,但是题目条件过于冗杂,并且没有想到将字符串使用list()函数转化为数组形式处理;没有思考在调用反转函数时,是部分反转而不是整个数组进行反转,所以此处应该用到切片;在循环遍历时,应该将指针每次按2k的单位进行移动,并且range函数是左闭右开的,第三个位置可以设置步长,此处就设置为2k。
2. 看完代码随想录的想法
(1)首先在内层定义一个函数,命名为reverse_string,用于对字符串数组进行反转:
使用双指针法,定义左指针和右指针,初始化存放于数组头和尾;然后以left < right为循环边界条件对数组进行遍历反转;首先定义一个中间遍量wrap,将左指针的值暂存wrap,然后将右指针的值赋值给左指针,然后将wrap存放的原左指针的值赋值给右指针,完成变量交换;接下来完成一次交换需要对左右指针进行更新,分别往中间移动一个单位;最后交换完成返回数组。
(2)对传入的字符串s进行类型转换,通过 list() 函数将它转换为数组类型nums_s。
(3)对数组进行切片循环遍历,设置指针i通过range()函数,[0, len(nums_s)),并且将循环步长设置为2*k;接下来调用上述定义的reverse_string函数对传入的切片数组[i:i+k]进行反转。
(4)拼接完成反转后的数组并返回。
class Solution:
def reverseStr(self, s: str, k: int) -> str:
# 定义一个反转函数,用于后续调用
def reverse_string(nums):
#定义左右指针用于反转数组
left = 0
right = len(nums)-1
while left < right:
wrap = nums[left]
nums[left] = nums[right]
nums[right] = wrap
left += 1
right -= 1
return nums
# 将字符串转换为数组形式,用于后续切片反转
nums_s = list(s)
for i in range(0, len(nums_s), 2k):
nums_s[i:i+k] = reverse_string(nums_s[i:i+k])
# 将切片并完成反转后的数组拼接起来,最终返回结果
return ''.join(nums_s)
三、卡码网:54.替换数字
建议:对于线性数据结构,填充或者删除,后序处理会高效的多。好好体会一下。题目链接/文章讲解:替换数字
1. 看到这道题的第一想法
没有考虑到数组空间是固定的,要扩充内存需要将size进行增加
以下代码未AC:
def reverseString(self, s: str) -> str:
list_s = list(s)
for i in range(len(list_s)):
if list_s[i].isnumeric()==True:
list_s[i] = 'number'
size+=1
return ''.join(list_s)
2. 看完代码随想录的想法
如果想把这道题目做到极致,就不要只用额外的辅助空间了! (不过使用Java刷题的录友,一定要使用辅助空间,因为Java里的string不能修改)
首先扩充数组到每个数字字符替换成 "number" 之后的大小。
例如 字符串 "a5b" 的长度为3,那么 将 数字字符变成字符串 "number" 之后的字符串为 "anumberb" 长度为 8。
如图:
然后从后向前替换数字字符,也就是双指针法,过程如下:i指向新长度的末尾,j指向旧长度的末尾。
为什么要从后向前填充,从前向后填充不行么?
从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素整体向后移动。
其实很多数组填充类的问题,其做法都是先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
这么做有两个好处:
- 不用申请新数组。
- 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。