题目链接:344. 反转字符串 - 力扣(LeetCode)
思路:
可以定义双指针分别指向字符串的一头一尾,再定义中间值tmp作为多出的O(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:
tmp = s[left]
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
题目链接:541. 反转字符串 II - 力扣(LeetCode)
思路:
在遍历字符串过程中,可以让i = 2*k,i每次移动2k个位置,对区间进行遍历,操作时也对区间进行切片操作,就会方便很多。
class Solution:
def reverseStr(self, s: str, k: int) -> str:
"""
1. 使用range(start, end, step)来确定需要调换的初始位置
2. 对于字符串s = 'abc',如果使用s[0:999] ===> 'abc'。字符串末尾如果超过最大长度,则会返回至字符串最后一个值,这个特性可以避免一些边界条件的处理。
3. 用切片整体替换,而不是一个个替换.
"""
def reverse_substring(text): # 自定义反转函数
left, right = 0, len(text) - 1
while left < right:
text[left], text[right] = text[right], text[left]
left += 1
right -= 1
return text
res = list(s)
for cur in range(0, len(s), 2 * k):
res[cur: cur + k] = reverse_substring(res[cur: cur + k])
return ''.join(res)
# 版本二
class Solution:
def reverseStr(self, s: str, k: int) -> str:
# Two pointers. Another is inside the loop.
p = 0
while p < len(s):
p2 = p + k
# Written in this could be more pythonic.
s = s[:p] + s[p: p2][::-1] + s[p2:] # s[:p]从头开始取到p位置,区间前闭后开
# s[p: p2][::-1]先取p到p2区间内的切片,区间前闭后开,再反转
# s[p2:]取p2开始及之后的所有切片,区间前闭后闭
p = p + 2 * k
return s
题目链接:剑指 Offer 05. 替换空格 - 力扣(LeetCode)
思路:
首先统计总共包含的空格个数,再扩充数组到每个空格替换成"%20"之后的大小,利用双指针法从后向前替换空格,i指向新长度的末尾,j指向旧长度的末尾
# 双指针法
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'
right -= 3
left -= 1
return ''.join(res)
# 版本二
class Solution:
def replaceSpace(self, s: str) -> str:
# method 1 - Very rude
return "%20".join(s.split(" "))
# method 2 - Reverse the s when counting in for loop, then update from the end.
n = len(s)
for e, i in enumerate(s[::-1]):
print(i, e)
if i == " ":
s = s[: n - (e + 1)] + "%20" + s[n - e:]
print("")
return s
题目链接:151. 反转字符串中的单词 - 力扣(LeetCode)
思路:
首先移除多余的空格,再将整个字符串反转,最后针对每个单词再做一次反转
class Solution:
#1.去除多余的空格
def trim_spaces(self, s):
n = len(s)
left = 0
right = n-1
while left <= right and s[left] == ' ': #去除开头的空格
left += 1
while left <= right and s[right] == ' ': #去除结尾的空格
right -= 1
tmp = []
while left <= right: #去除单词中间多余的空格
if s[left] != ' ':
tmp.append(s[left])
elif tmp[-1] != ' ': #当前位置是空格,但是相邻的上一个位置不是空格,则该空格是合理的
tmp.append(s[left])
left += 1
return tmp
#2.翻转字符数组
def reverse_string(self, nums, left, right):
while left < right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
return None
#3.翻转每个单词
def reverse_each_word(self, nums):
start = 0
end = 0
n = len(nums)
while start < n:
while end < n and nums[end] != ' ':
end += 1
self.reverse_string(nums, start, end-1)
start = end + 1
end += 1
return None
#4.翻转字符串里的单词
def reverseWords(self, s): #测试用例:"the sky is blue"
l = self.trim_spaces(s) #输出:['t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'
self.reverse_string(l, 0, len(l)-1) #输出:['e', 'u', 'l', 'b', ' ', 's', 'i', ' ', 'y', 'k', 's', ' ', 'e', 'h', 't']
self.reverse_each_word(l) #输出:['b', 'l', 'u', 'e', ' ', 'i', 's', ' ', 's', 'k', 'y', ' ', 't', 'h', 'e']
return ''.join(l) #输出:blue is sky the
class Solution:
def reverseWords(self, s: str) -> str:
# method 1 - Rude but work & efficient method.
s_list = [i for i in s.split(" ") if len(i) > 0]
return " ".join(s_list[::-1])
# method 2 - Carlo's idea
def trim_head_tail_space(ss: str):
p = 0
while p < len(ss) and ss[p] == " ":
p += 1
return ss[p:]
# Trim the head and tail space
s = trim_head_tail_space(s)
s = trim_head_tail_space(s[::-1])[::-1]
pf, ps, s = 0, 0, s[::-1] # Reverse the string.
while pf < len(s):
if s[pf] == " ":
# Will not excede. Because we have clean the tail space.
if s[pf] == s[pf + 1]:
s = s[:pf] + s[pf + 1:]
continue
else:
s = s[:ps] + s[ps: pf][::-1] + s[pf:]
ps, pf = pf + 1, pf + 2
else:
pf += 1
return s[:ps] + s[ps:][::-1] # Must do the last step, because the last word is omit though the pointers are on the correct positions,
题目链接:剑指 Offer 58 - II. 左旋转字符串 - 力扣(LeetCode)
思路:
首先,一般的思路即为n个for循环,分别将后面n-1个数前移,再将第0位数放在最后一位,重复k次即可完成。
关键在于此题思路的进阶版,联想上一题的整体反转加局部反转即可实现此题的要求,而且没有申请额外的空间,仅在本串上操作。具体步骤为:1反转区间为前k的子串 2反转区间为k到末尾的子串 3反转整个字符串
# 方法一:可以使用切片方法
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[n:] + s[0:n]
# 方法二:也可以使用上文描述的方法
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
s = list(s)
s[0:n] = list(reversed(s[0:n]))
s[n:] = list(reversed(s[n:]))
s.reverse()
return "".join(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