344.反转字符串
题目链接:https://leetcode.cn/problems/reverse-string/
题目描述:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
案例:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
实现:
方法一:
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
s[::-1]表示反转s中的元素
s[:]表示数组中所有子模块
"""
s[:]=s[::-1] #将原数组反转后赋值给s中每一个对应的位置
方法二:双指针
初始化:设置两个指针l和r分别指向列表首尾元素
步骤:交换s[l]和s[r]对应元素,并更新指针位置(l+=1,r-=1),直到两个指针相遇
时间复杂度:O(N)
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
l,r = 0,len(s)-1
while l<r:
s[l],s[r] = s[r],s[l]
l += 1
r -= 1
541. 反转字符串II
题目链接:https://leetcode.cn/problems/reverse-string-ii/
题目描述:给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
案例:
输入: s = "abcdefg", k = 2
输出: "bacdfeg"
实现:
class Solution:
def reverseStr(self, s: str, k: int) -> str:
p = 0
while p < len(s):
p2 = p + k
s = s[:p] + s[p:p2][::-1] + s[p2:]
p = p + 2*k
return s
剑指Offer 05.替换空格
题目链接:https://leetcode.cn/problems/ti-huan-kong-ge-lcof/
题目描述:请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
案例:
1: 输入:s = "We are happy."
输出:"We%20are%20happy."
实现:
方法一:遍历添加
在 Python 和 Java 等语言中,字符串都被设计成「不可变」的类型,即无法直接修改字符串的某一位字符,需要新建一个字符串实现。
算法流程:
初始化一个 list (Python) / StringBuilder (Java) ,记为 res ;
遍历列表 s 中的每个字符 c :
当 c 为空格时:向 res 后添加字符串 “%20” ;
当 c 不为空格时:向 res 后添加字符 c ;
将列表 res 转化为字符串并返回。
复杂度分析:
时间复杂度 O(N)O(N)O(N) : 遍历使用 O(N)O(N)O(N) ,每轮添加(修改)字符操作使用 O(1)O(1)O(1) ;
空间复杂度 O(N)O(N)O(N) : Python 新建的 list 和 Java 新建的 StringBuilder 都使用了线性大小的额外空间。
class Solution:
def replaceSpace(self, s: str) -> str:
res = []
for c in s:
# 当 c 为空格时:向 res 后添加字符串 "%20"
if c == ' ': res.append("%20")
# 当 c 不为空格时:向 res 后添加字符 c
else : res.append(c)
# 将列表 res 转化为字符串并返回
return "".join(res)
方法二:双指针法
首先扩充数组到每个空格替换成"%20"之后的大小。
然后从后向前替换空格,也就是双指针法,过程如下:
i指向新长度的末尾,j指向旧长度的末尾。
class Solution:
def replaceSpace(self, s: str) -> str:
counter = s.count(' ')
res = list(s) #转换为列表
# 每碰到一个空格就多扩展两个格子
res.extend([' ']* counter * 2)
# left为原字符串的末尾,right为拓展长度后的末尾
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)
之前完成的双指针解法相关的题目有:
151.翻转字符串里的单词
题目链接:https://leetcode.cn/problems/reverse-words-in-a-string/
题目描述:给你一个字符串 s
,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s
中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
**注意:**输入字符串 s
中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
案例:
示例1:
输入: "the sky is blue"
输出: "blue is sky the"
示例2:
输入:s = " hello world "
输出:"world hello"
解释:反转后的字符串中不能存在前导空格和尾随空格。
示例3:
输入:s = "a good example"
输出:"example good a"
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。
思路:
- 移除多余空格
- 将整个字符串反转
- 将每个单词反转
举个例子,源字符串为:"the sky is blue "
- 移除多余空格 : “the sky is blue”
- 字符串反转:“eulb si yks eht”
- 单词反转:“blue is sky the”
实现:
方法一:
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=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
# 测试用例:"the sky is blue"
def reverseWords(self, s: str) -> str:
#输出:['t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'
l = self.trim_spaces(s)
#输出:['e', 'u', 'l', 'b', ' ', 's', 'i', ' ', 'y', 'k', 's', ' ', 'e', 'h', 't']
self.reverse_string( l, 0, len(l) - 1)
#输出:['b', 'l', 'u', 'e', ' ', 'i', 's', ' ', 's', 'k', 'y', ' ', 't', 'h', 'e']
self.reverse_each_word(l)
#输出:blue is sky the
return ''.join(l)
方法二:双指针法
算法解析:
倒序遍历字符串 sss ,记录单词左右索引边界 iii , jjj ;
每确定一个单词的边界,则将其添加至单词列表 resresres ;
最终,将单词列表拼接为字符串,并返回即可。
复杂度分析:
时间复杂度 O(N)O(N)O(N) : 其中 NNN 为字符串 sss 的长度,线性遍历字符串。
空间复杂度 O(N)O(N)O(N) : 新建的 list(Python) 或 StringBuilder(Java) 中的字符串总长度 ≤N\leq N≤N ,占用 O(N)O(N)O(N) 大小的额外空间。
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip() #删除首尾空格
i = j = len(s) -1
res = []
while i>= 0:
# 搜索首个空格
while i >= 0 and s[i] != ' ': i -= 1
# 添加单词
res.append(s[i + 1 : j + 1])
# 跳过单词间的空格
while s[i] == ' ': i -= 1
# j指向下个单词的尾字符
j = i
# 凭借并返回
return ' '.join(res)
剑指Offer58-II.左旋转字符串
题目链接:https://leetcode.cn/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
题目描述:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
案例:
输入: s = "abcdefg", k = 2
输出: "cdefgab"
实现:
方法一:切片
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)
# 1.反转区间为前n的子串
s[0:n] = list(reversed(s[0:n]))
# 2.反转区间为n到末尾的子串
s[n:] = list(reversed(s[n:]))
# 3.反转整个字符串
s.reverse()
return "".join(s)
方法三:
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