今日题目
344.反转字符串
题目链接:344. 反转字符串 - 力扣(LeetCode)
思考:将字符串反过来,就是以数组中间位置为轴,水平旋转180度。最简单办法就是新建一个数组,倒序遍历原数组并逐个位置赋值给新数组。
题目要求不要给另外的数组分配额外的空间,必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。因此不能开辟一个新数组。
这道题关键是以数组中间位置为轴,首先需要找到需要互换位置的元素下标关系,仔细思考不难发现,互换位置的下标关系为(index, -index-1)或者(index, len(s)-index-1),len(s)为数组长度。发现这个互换位置下标关系,其实就解决了一半。剩下的一半,就是何时停止互换。
我刚开始写的时候没考虑停止,就觉得这样遍历完整个数组就行了。然而,当index达到数组中间位置后,后面的遍历互换会导致已经被换好的元素被换回去,和原始数组一样。因此,数组中间位置就是停止互换的条件,即len(s)//2。那么应该是index<len(s)//2,还是index<=len(s)//2呢?可以举例思考:
假设数组只有偶数个元素,比如4个,["h","e","l","l"],index只需走过"h","e"就可以了,"e"下标为1,len(s)//2=2,因此需要index<len(s)//2,无需=的情况。
代码:
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
for index, string in enumerate(s):
if index < len(s) // 2:
tmp = s[-index-1]
s[-index-1] = string
s[index] = tmp
else:
return s
return s
541. 反转字符串II
题目链接:541. 反转字符串 II - 力扣(LeetCode)
思考:本题与上面一题类似,区别在于:1、输入不是列表,而是一整个字符串;2、分段反转字符串。
首先想到的就是先把输入字符串转成类似上面一题的列表形式,然后就是定位区间,每个区间上的思路与上题方法一致。为了完整显示定位区间的思想,我的代码比较冗余,每一段都做了细致的判断和处理。(见解法一)
仔细观察解法一,会发现很多代码存在重复,其实可以封装起来,而且定位区间的判断较多,显得代码更为复杂。
总结一下区间的移动,其实就是每一个长度为2k的区间中,处理前k个字符串,进行反转。(每次反转都是对这一段字符串全部反转,其实不够k个与k个的反转是一样的)。
因此,考虑把反转的功能封装为一个函数,在长度为k的区间上处理字符串。程序整体按照2k为步长去遍历数组。(见解法二)
其实两种解法一个意思,只不过第一种分的太细了,第二种进行了封装简化。(鲜明的对比,高端的程序员往往只用最少的代码)
代码:
# 解法一
class Solution:
def reverseStr(self, s: str, k: int) -> str:
l_s = list(s)
n = len(l_s)
if n < k:
for i in range(n // 2):
l_s[i], l_s[-1-i] = l_s[-1-i], l_s[i]
return ''.join(l_s)
elif n >= k and n < 2*k:
for i in range(k // 2):
l_s[i], l_s[k-1-i] = l_s[k-1-i], l_s[i]
return ''.join(l_s)
else:
pre_n, pos_n = divmod(n, 2*k)
for i in range(pre_n):
start = 2*k*i
end = 2*k*(i+1)
cur = l_s[start:end]
for i in range(k // 2):
cur[i], cur[k-1-i] = cur[k-1-i], cur[i]
l_s[start:end] = cur
last = l_s[-pos_n:]
if pos_n == 0:
return ''.join(l_s)
elif pos_n < k:
for i in range(pos_n // 2):
last[i], last[-1-i] = last[-1-i], last[i]
l_s[-pos_n:] = last
return ''.join(l_s)
else:
for i in range(k // 2):
last[i], last[k-1-i] = last[k-1-i], last[i]
l_s[end:] = last
return ''.join(l_s)
# 解法二
class Solution:
def reverseStr(self, s: str, k: int) -> str:
l_s = list(s)
for i in range(0, len(l_s), 2*k):
l_s[i:i+k] = self.reverse_list(l_s[i:i+k])
return ''.join(l_s)
def reverse_list(self, l_s):
l_n = len(l_s)
for i in range(l_n // 2):
l_s[i], l_s[-1-i] = l_s[-1-i], l_s[i]
return l_s
卡码网:54.替换数字
题目链接:54. 替换数字(第八期模拟笔试)
思考:需要把数字出现的位置上数字换为number,由于原本一个长度的变成了6个长度,后面的元素就要向后移动,这样操作很麻烦,因为还需要插入空位置。
所以,首先创建一个足够长度的空字符数组,然后从数组末尾开始填写字符,原数组也是从末尾开始进行遍历,逐个判断,如果是字母就直接写到新数组中,如果是数字,就要把当前下标到前面的6个位置写入number。直到遍历到原数组开头位置为止。
代码:
def main():
data = input()
count = sum(1 for char in data if char.isdigit())
expand_len = len(data) + (count * 5)
res = [''] * expand_len
new_index = expand_len - 1
old_index = len(data) - 1
while old_index >= 0:
if data[old_index].isdigit():
res[new_index-5:new_index+1] = "number"
new_index -= 6
else:
res[new_index] = data[old_index]
new_index -= 1
old_index -= 1
result = "".join(res)
print(result)
if __name__ == "__main__":
main()