344.反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
思路:首先排除最简单的暴力法,需要额外的O(n)空间,不是原地修改。由于题目要求原地修改数组,那么立马就想到交换字符,即头和尾交换字符。设置left和right 指针,每做一次循环后进行一次相向平移,直到left和right指针相遇结束。
代码如下:
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
这个题目很基础,所以趁此多接触一些其他的方法。
使用栈(后进先出,所以pop后尾会变成头,以此实现倒序,但理解应该是用了额外空间的):
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()
直接使用自带的函数reversed:
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
s[:] = reversed(s)
使用自带的字符串reverse函数:
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
# 原地反转,无返回值
s.reverse()
以上reversed和reverse进行区分:
reverse() 方法:
- 是列表(list)对象的一个方法。
- 用于就地(in-place)反转列表中的元素,也就是说它直接修改原列表,而不返回新列表。
- 没有返回值(即返回 None)。
- 只能用于可变序列,比如列表。
reversed() 函数:
- 是一个内建函数,可以用于反转任何支持迭代的对象,如列表、元组、字符串等。
- 不会就地修改原序列,而是返回一个新的反转迭代器。
- 需要通过 list() 函数或其他方式来转换为列表或其他数据结构。
- 可以用于不可变序列,如元组。
使用切片:
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[:] = [s[i] for i in range(len(s) - 1, -1, -1)]
541. 反转字符串II
给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = "abcdefg", k = 2
输出: "bacdfeg"
思路其实没有什么特殊的,自然就是起点往后k个字符进行reverse,然后令起点往后移2k个字符,然后循环重复以上过程。需要注意的是,需要分两种情况:【起点+k大于字符串尾部】和【起点+k小于字符串尾部】,如果大于则直接将剩下部分全部反序,如果小于则可以顺利执行以上过程。
思路一直是这样没问题,但是由于对str类型的操作不够熟练,导致反复在用法上卡bug,例如:错误信息 TypeError: 'str' object does not support item assignment 表示你尝试对一个字符串对象进行项赋值操作,但是字符串(str)在 Python 中是不可变的(immutable),这意味着你不能改变字符串中的单个字符。
在 Python 中,字符串被视为一系列字符的序列,但是一旦创建,你就不能更改它。尝试像这样修改字符串中的某个位置的字符会引发类型错误:
python
s = "hello"
s[0] = "H" # 这会引发 TypeError
如果你需要修改字符串中的字符,你可以通过创建一个新的字符串来实现。例如,你可以使用字符串切片和拼接来创建一个修改后的字符串:
python
s = "hello"
s = "H" + s[1:] # 创建一个新的字符串 "Hello"
如果你在处理列表中的字符串,并且想要交换两个字符串元素的位置,你可以这样做:
python
s = ["hello", "world"]
s[0], s[1] = s[1], s[0] # 交换列表中的两个元素
在这个例子中,s 是一个列表,列表是可变的,所以你可以更改列表中的元素。这里我们交换了列表中第一个和第二个元素的位置。
如果你确实需要修改字符串中的字符,并且想要原地修改(in-place),你需要将字符串转换为列表(因为列表是可变的),修改列表,然后再将列表转换回字符串。这里是如何做到这一点的例子:
python
s = list("hello") # 将字符串转换为列表
s[0], s[1] = s[1], s[0] # 现在可以交换元素了
s = "".join(s) # 将列表转换回字符串
在这个例子中,我们首先将字符串 "hello" 转换为字符列表 ['h', 'e', 'l', 'l', 'o'],然后交换了列表中的第一个和第二个元素,最后使用 "".join(s) 将列表转换回字符串 "elloh"。
另外记录一个当时在debug的时候自己也想到的思路,但是因为字符串操作太生疏没通过的例子,在这里直接附代码不复现了:
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
替换数字
给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。
例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。
对于输入字符串 "a5b",函数应该将其转换为 "anumberb"
输入:一个字符串 s,s 仅包含小写字母和数字字符。
输出:打印一个新的字符串,其中每个数字字符都被替换为了number
样例输入:a1b2c3
样例输出:anumberbnumbercnumber
数据范围:1 <= s.length < 10000。
思路:很简单,对字符串进行遍历,遍历到数字将其转化为’number’,python直接使用字符串切片进行重新拼接即可。而在C++等可以直接对str进行修改的语言里,可以先遍历字符串统计数字的个数,然后再根据需要扩容原字符串,需要注意的是,在这个情况下,要进行替换操作一定应该倒序操作,因为只有倒序操作复杂度才是O(n),如果正序操作的话需要额外遍历将索引后面的字符串后移,导致复杂度增加变成O(n²)。所以记录一下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;
}}
Python写法:
可以先将字符串转换为list,由于每个元素都是一个单独的字符,可以直接将字符替换为字符串’number’然后再重新拼接,所以不涉及平移的操作,直接令number[i]=’number’即可。代码如下:
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)
以下是ACM输入模式下,自己的复现:
def main():
data = input()
d = list(data)
for i in range(len(d)):
if d[i].isdigit(): # 也可以用ascii码, if ord("0") <= ord(d[i]) <= ord("9"):
d[i] = 'number'
data = "".join(d)
print(data)
if __name__ == "__main__":
main()