文章目录
前言
344.反转字符串
思路 双指针
讲解:反转字符串依然是使用双指针的方法,只不过对于字符串的反转,其实要比链表简单一些。因为字符串也是一种数组,所以元素在内存中是连续分布,这就决定了反转链表和反转字符串方式上还是有所差异的。
如果是c++,可以用库函数reverse()函数,也可以用swap函数来交换两个数,但是本题肯定是不希望使用库函数,肯定是想让大家了解库函数的内部实现。
本题正式解体思路和我自己的思路一样,很简单;
使用左右双指针:都是从最左边最右边开始同时往中间移动;
边界情况:是<n//2还是<=n//2,代入检验就行
【到这里要学会了快速检验;例如长度为4,n//2为2,肯定是<;如果是5的话,也是截止到1的index,所以<】
python交换位置的方法
- 使用元组交换:a, b = b, a
自己写的小细节:
3.
方法一 双指针
"""
我自己写的,元组交换
"""
class Solution(object):
def reverseString(self, s):
"""
:type s: List[str]
:rtype: None Do not return anything, modify s in-place instead.
"""
n = len(s)
left, right = 0, n-1
while left < n//2 :
s[left],s[right] = s[right],s[left]
left += 1
right -= 1
return s
方法二 使用栈、slice、reverse、reversed等
但是我觉得这个方法多了一个栈,需要多开辟一个空间,但是速度快
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
stack = []
for char in s:
stack.append(char)
for i in range(len(s)):
s[i] = stack.pop()
调用函数使用slice切片、reverse、reversed
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
s[:] = s[::-1]
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
# 原地反转,无返回值
s.reverse()
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
s[:] = reversed(s)
# 列表推导
s[:] = [s[i] for i in range(len(s) - 1, -1, -1)]
# range
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
n = len(s)
for i in range(n // 2):
s[i], s[n - i - 1] = s[n - i - 1], s[i]
541. 反转字符串II
思路
核心想法:for循环的时候每一次迭代都是2k来进行迭代,i += (2 * k);而不是习惯性的i++,然后再判断是否有需要翻转的区间;
主要思路:固定i,判断i+k是否存在,存在就翻转,不存在就有多少翻多少
注意小细节:
- 一般库函数中的reverse都是左闭右开
- 翻转的时候,传入数组s,起始index
- 注意边界:(仍然是代入检验)i+k是<还是<=numsize?A:因为是左闭右开,所以包括=
方法一 自己写的
直接参考后面的,自己写的修修补补
自己写的注意点
-
python数组一段进行reverse函数的实现:我是额外写的一个使用range的reverse函数
-
python的slice是n[start:stop:step]但是注意不到stop,别忘了。。🧁
-
定义函数的时候不要写出这种错误啊:def reverse1(self,s,i,i+k):很离谱的。。。。k是哪来的??应该是def reverse1(self,s,i,k)==
-
报错:是因为python不可以直接处理字符串,不可以改动,要转换成list(S),最后return ‘’.join(S)才可以
5. 用了while之后每一种情况都需要加i+= 2k,我一开始continue忘记写了
class Solution(object):
def reverse1(self,s,i,k):
s[i:k] = [s[j] for j in range(k-1,i-1,-1)]
def reverseStr(self, s, k):
"""
:type s: str
:type k: int
:rtype: str
"""
n = len(s)
i = 0
s = list(s)
while i < n:
# 判断i+k的情况
if i+k <= n:
self.reverse1(s,i,i+k)
i += 2*k #莫要漏了
continue #第二种情况,有k个字符串,满足了就进入下一个循环
#如果i+k超过范围了,就直接倒
self.reverse1(s,i,n)
i += 2*k
return ''.join(s)
方法二 参考代码-多学习
第一种:利用双指针;最重要的是超过的切片python会返回最大长度,不用担心边界条件,艹;
对于字符串s = ‘abc’,如果使用s[0:999] ===> ‘abc’。字符串末尾如果超过最大长度,则会返回至字符串最后一个值,这个特性可以避免一些边界条件的处理。
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)
第二种:代码很简洁,只需要把中间一段[::-1]就行,天才!
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:]
p = p + 2 * k
return s
卡码网:54.替换数字
思路
本题针对c++语言才有意义,python完全没有用,python太好写了;我已经在考虑改语言了。啊好烦;
方法一
python就很简单,注意判断语句**isdigit()**背诵一下就行
或者用s[i] >= ‘0’ && s[i] <= '9’也可以(python加个ord,我这是扣的c++代码)
class Solution:
def change(self, s):
lst = list(s) # Python里面的string也是不可改的,所以也是需要额外空间的。空间复杂度:O(n)。
for i in range(len(lst)):
if lst[i].isdigit():
lst[i] = "number"
return ''.join(lst)
方法二 c++
c++写的话,需要扩容所以总体思路为:
首先判断有多少数字,计算扩容之后的数组空间大小之后,使用双指针从后往前填充,很巧妙!!
#include <iostream>
using namespace std;
int main() {
string s;
while (cin >> s) {
int sOldIndex = s.size() - 1;
int count = 0; // 统计数字的个数
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '0' && s[i] <= '9') {
count++;
}
}
// 扩充字符串s的大小,也就是将每个数字替换成"number"之后的大小
s.resize(s.size() + count * 5);
int sNewIndex = s.size() - 1;
// 从后往前将数字替换为"number"
while (sOldIndex >= 0) {
if (s[sOldIndex] >= '0' && s[sOldIndex] <= '9') {
s[sNewIndex--] = 'r';
s[sNewIndex--] = 'e';
s[sNewIndex--] = 'b';
s[sNewIndex--] = 'm';
s[sNewIndex--] = 'u';
s[sNewIndex--] = 'n';
} else {
s[sNewIndex--] = s[sOldIndex];
}
sOldIndex--;
}
cout << s << endl;
}
}
拓展 c++
151.翻转字符串里的单词
思路
读题尤其注意:单词之间可能会有多个空格的,需要变成一个空格
简单方法:
- 空间复杂度不为O(1)也就是创建一个新的数组,失去了这道题目的意义
- 调用库函数:比如使用split,然后concat使用‘ ’,也可以不用
- 使用erase来删除空格:也不,因为erase删除的时间复杂度为O(n)
总体思路:首先使用快慢指针将多余的空格去掉,然后先先总体reverse之后再对单个字母reverse,得到我们想要的结果
举个例子,源字符串为:"the sky is blue "
移除多余空格 : “the sky is blue”
字符串反转:“eulb si yks eht”
单词反转:“blue is sky the”
方法一: 针对python
class Solution:
def reverseWords(self, s: str) -> str:
# 删除前后空白
s = s.strip()
# 反转整个字符串
s = s[::-1]
# 将字符串拆分为单词,并反转每个单词
s = ' '.join(word[::-1] for word in s.split())
return s
使用双指针
class Solution:
def reverseWords(self, s: str) -> str:
# 将字符串拆分为单词,即转换成列表类型
words = s.split()
# 反转单词
left, right = 0, len(words) - 1
while left < right:
words[left], words[right] = words[right], words[left]
left += 1
right -= 1
# 将列表转换成字符串
return " ".join(words)
方法二 按照讲解的来
因为python的for语句执行逻辑是:无论如何处理fast指针,只要到for语句,它都是一个一个往后移动;比如说我已经处理到3了,过了一下for,又从1开始。
所以讲解完全不能用;不写了,根本没时间。
python还有一个限制是,没有resize,去除空格之后多余的部分删除不了
会出现下面的结果
class Solution(object):
def reverse1(self,s,i,k):
s[i:k] = [s[j] for j in range(k-1,i-1,-1)]
def removeExtraSpaces(self,s):
slow, fast = 0, 0
# for fast in range(0,len(s)):#绝对不能用for,python里面for会一个一个加的
while fast < len(s):
if s[fast] != ' ':
if slow !=0:#手动给单词开头加空格
s[slow] = ' '
slow += 1
while fast < len(s) and s[fast] != ' ':
# print("slow "+s[slow]+" "+str(slow))
s[slow] = s[fast]
fast += 1
slow += 1
else:
fast += 1
def reverseWords(self, s):
"""
:type s: str
:rtype: str
"""
s = list(s)
n = len(s)
self.removeExtraSpaces(s)
print(s)
self.reverse1(s,0,n)
#下面开始翻转单个字符,也是使用双指针的方法
start = 0#慢指针
for i in range(0,n+1): #左闭右开
if i == n or s[i] == ' ':#如果到最后了或者是空格,说明可以翻转了
self.reverse1(s,start,i)
start = i + 1
print(s)
return s
卡码网:55.右旋转字符串
思路
使用整体反转+局部反转就可以实现反转单词顺序的目的
首先整体翻转一下,然后将两个部分分别翻转就可以得到想要的结果【不懂看讲解】
卡码网的代码需要自己写输入输出,海康的题目就是这样的🥚
自己写的错误:记得输入的k要加一个int
#获取输入的数字k和字符串
k = int(input())
s = input()
#通过切片反转第一段和第二段字符串
#注意:python中字符串是不可变的,所以也需要额外空间
s = s[len(s)-k:] + s[:len(s)-k]
print(s)
总结
c++和python还是差太多了,空间分配不一样,二刷一定要用c++,一刷了解算法思想