344. 反转字符串
难度:☆1
数组,相向双指针。一个指针从前往后,另一个指针从后往前,碰头之前交换它们指向的字符。
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
left, right = 0, len(s) - 1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
本题一行代码解决反转字符串的 Python 内置函数是 s.reverse()
。
541. 反转字符串 II
难度:☆4
根据题意模拟,注意每次循环递增量是2 * k。考察了Python语言特性:字符串切片、list()字符串转化为列表、循环递增量、reversed()、join()列表转化为字符串。
策略:反转本身的Python实现有自定义函数、reversed()、切片几种。
a. 自定义反转函数
参考344. 反转字符串。先把字符串转化为列表,最后把列表转化为字符串。
class Solution:
def reverseStr(self, s: str, k: int) -> str:
result = list(s)
for i in range(0, len(s), 2 * k):
result[i: i + k] = self.reverseSubstring(result[i: i + k])
return ''.join(result)
def reverseSubstring(self, s: List[str]) -> List[str]:
left, right = 0, len(s) - 1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
return s
b. reversed()
用Python内置函数。先把字符串转化为列表,最后把列表转化为字符串。
class Solution:
def reverseStr(self, s: str, k: int) -> str:
result = list(s)
for i in range(0, len(s), 2 * k):
result[i: i + k] = reversed(result[i: i + k])
return ''.join(result)
c. 切片相加
不用字符串-列表转化,在字符串原位操作反转、相加。注意 [::-1]
的写法和位置。
class Solution:
def reverseStr(self, s: str, k: int) -> str:
p = 0
while p < len(s):
s = s[:p] + s[p: p + k][::-1] + s[p + k:]
p += 2 * k
return s
剑指 Offer 05. 替换空格
难度:☆2
a. 数组原地扩容
字符串转化为列表,列表扩容字符串长度的两倍(耗费太多空间,不采用),或扩容空格个数的两倍(双指针,从后向前倒序填充,不用申请额外数组空间)。列表的扩容用到 extend() 方法。
class Solution:
def replaceSpace(self, s: str) -> str:
counter = s.count(' ')
res = list(s)
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:
res[right - 2: right + 1] = '%20'
right -= 3
left -= 1
return ''.join(res)
b. Python内置函数
一行代码解决,仅作参考,不可偷懒。
class Solution:
def replaceSpace(self, s: str) -> str:
return "%20".join(s.split(" "))
class Solution:
def replaceSpace(self, s: str) -> str:
return s.replace(' ', '%20')
151. 反转字符串中的单词
难度:☆5
a. 字符串操作
分布操作:1 去掉多余空格,2 翻转整个字符串,3 翻转每个单词。其中翻转字符的函数可以翻转整个字符串,也可以由翻转每个单词的函数调用。第2、3步是原地操作。
难以独立做出来,需要再反复研究。
class Solution:
def trim_spaces(self, s: str) -> list:
left, right = 0, len(s) - 1
# 去掉字符串开头的空白字符
while left <= right and s[left] == ' ':
left += 1
# 去掉字符串末尾的空白字符
while left <= right and s[right] == ' ':
right -= 1
# 将字符串间多余的空白字符去除
output = []
while left <= right:
if s[left] != ' ':
output.append(s[left])
elif output[-1] != ' ':
output.append(s[left])
left += 1
return output
def reverse(self, l: list, left: int, right: int) -> None:
while left < right:
l[left], l[right] = l[right], l[left]
left, right = left + 1, right - 1
def reverse_each_word(self, l: list) -> None:
n = len(l)
start = end = 0
while start < n:
# 循环至单词的末尾
while end < n and l[end] != ' ':
end += 1
# 翻转单词
self.reverse(l, start, end - 1)
# 更新start,去找下一个单词
start = end + 1
end += 1
def reverseWords(self, s: str) -> str:
# 去掉多余空格
l = self.trim_spaces(s)
# 翻转字符串
self.reverse(l, 0, len(l) - 1)
# 翻转每个单词
self.reverse_each_word(l)
# 字符列表重组为字符串输出
return ''.join(l)
b. 双端队列
维护一个word列表,将单词暂存于word列表中,appendleft到deque中完成翻转,清空word列表,再存下一个单词。不需要多个函数,代码少。
class Solution:
def reverseWords(self, s: str) -> str:
left, right = 0, len(s) - 1
# 去掉字符串开头的空白字符
while left <= right and s[left] == ' ':
left += 1
# 去掉字符串末尾的空白字符
while left <= right and s[right] == ' ':
right -= 1
d, word = collections.deque(), []
# 将单词 push 到队列的头部
while left <= right:
if s[left] == ' ' and word:
d.appendleft(''.join(word))
word = []
elif s[left] != ' ':
word.append(s[left])
left += 1
d.appendleft(''.join(word))
return ' '.join(d)
c. Python内置函数
一行代码解决,仅作参考,不可偷懒。
class Solution:
def reverseWords(self, s: str) -> str:
return ' '.join(reversed(s.split()))
class Solution:
def reverseWords(self, s: str) -> str:
return ' '.join(s.split()[::-1])
剑指 Offer 58 - II. 左旋转字符串
难度:☆1
a. 局部反转+整体反转
左右侧分别反转,合并,再整体反转。具体步骤为:反转区间为前n的子串,反转区间为n到末尾的子串,反转整个字符串。最后就可以达到左旋n的目的。优点:完全在本串上操作,而不用定义新的字符串。
用切片反转:
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return (s[:n][::-1] + s[n:][::-1])[::-1]
用内置函数反转:
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
s = list(s)
s[:n] = reversed(s[:n])
s[n:] = reversed(s[n:])
return ''.join(reversed(s))
用自定义的函数反转:
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
lst = list(s)
end = len(lst) - 1
self.reverseSub(lst, 0, n-1)
self.reverseSub(lst, n, end)
self.reverseSub(lst, 0, end)
return ''.join(lst)
def reverseSub(self, lst, left, right):
while left < right:
lst[left], lst[right] = lst[right], lst[left]
left += 1
right -= 1
b. 整体反转+局部反转
具体步骤为:反转整个字符串,反转区间为前 len(s)-n 的子串,反转区间为 len(s)-n 到末尾的子串。
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[::-1][:len(s)-n][::-1] + s[::-1][len(s)-n:][::-1]
c. 切片+交换位置
Python切片,再交换位置合并。
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[n:] + s[:n]
d. 扩展字符串+切片
字符串扩展一遍,再切 [n:n+length] 的部分即可。
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
length = len(s)
s += s
return s[n:n+length]
e. 双端队列
把字符串放进一个双端队列deque,左侧的弹出来压入右侧。缺点:要另外开辟空间存放s的字符。
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
d = deque()
for i in s:
d.append(i)
for _ in range(n):
left = d.popleft()
d.append(left)
return ''.join(d)