Easy
题目描述
给你一个字符串 s ,根据下述规则反转字符串:
- 所有非英文字母保持在原有位置上。
- 所有英文字母(小写或大写)位置反转。
返回反转后的 s 。
示例 1:
输入: s = "ab-cd"
输出: "dc-ba"
示例 2:
输入: s = "a-bC-dEf-ghIj"
输出: "j-Ih-gfE-dCba"
示例 3:
输入: s = "Test1ng-Leet=code-Q!"
输出: "Qedo1ct-eeLg=ntse-T!"
提示:
1 <= s.length <= 100s由 ASCII 值在范围[33, 122]的字符组成s不含'\"'或'\\'
解题思路
解题思路
这道题要求仅仅反转字符串中的英文字母,而非字母字符保持原位置不变。
方法一:双指针法(推荐)
使用双指针从字符串两端向中间移动:
- 左指针从左侧寻找英文字母,右指针从右侧寻找英文字母
- 当两个指针都找到字母时,交换它们的位置
- 继续移动指针,直到两指针相遇
这种方法时间复杂度最优,空间复杂度也最小。
方法二:栈辅助法
先遍历字符串,将所有字母压入栈中,然后再次遍历字符串,遇到字母位置就从栈中弹出元素替换。
方法三:额外数组法
将字符串转为字符数组,提取所有字母并反转,然后按原顺序填回字母位置。
双指针法是最优解,因为它原地操作,不需要额外的数据结构。
代码实现
class Solution {
public:
string reverseOnlyLetters(string s) {
int left = 0, right = s.length() - 1;
while (left < right) {
// 左指针寻找字母
while (left < right && !isalpha(s[left])) {
left++;
}
// 右指针寻找字母
while (left < right && !isalpha(s[right])) {
right--;
}
// 交换字母
if (left < right) {
swap(s[left], s[right]);
left++;
right--;
}
}
return s;
}
};
class Solution:
def reverseOnlyLetters(self, s: str) -> str:
s = list(s)
left, right = 0, len(s) - 1
while left < right:
# 左指针寻找字母
while left < right and not s[left].isalpha():
left += 1
# 右指针寻找字母
while left < right and not s[right].isalpha():
right -= 1
# 交换字母
if left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
return ''.join(s)
public class Solution {
public string ReverseOnlyLetters(string s) {
char[] chars = s.ToCharArray();
int left = 0, right = s.Length - 1;
while (left < right) {
// 左指针寻找字母
while (left < right && !char.IsLetter(chars[left])) {
left++;
}
// 右指针寻找字母
while (left < right && !char.IsLetter(chars[right])) {
right--;
}
// 交换字母
if (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
}
return new string(chars);
}
}
var reverseOnlyLetters = function(s) {
const chars = s.split('');
let left = 0, right = s.length - 1;
while (left < right) {
// 左指针寻找字母
while (left < right && !isLetter(chars[left])) {
left++;
}
// 右指针寻找字母
while (left < right && !isLetter(chars[right])) {
right--;
}
// 交换字母
if (left < right) {
[chars[left], chars[right]] = [chars[right], chars[left]];
left++;
right--;
}
}
return chars.join('');
function isLetter(char) {
return (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z');
}
};
复杂度分析
| 复杂度类型 | 复杂度 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(1) 对于C++;O(n) 对于其他语言(字符串不可变需要转换为数组) |
其中 n 为字符串长度。每个字符最多被访问一次,时间复杂度为 O(n)。C++ 可以直接修改字符串,空间复杂度为 O(1);其他语言由于字符串不可变特性,需要额外的字符数组空间。