Easy

题目描述

给定一个由小写英文字母和特殊字符组成的字符串 s

你需要按顺序执行以下操作:

  1. 反转小写字母,并将它们放回原本字母占据的位置。
  2. 反转特殊字符,并将它们放回原本特殊字符占据的位置。

返回执行反转操作后的结果字符串。

示例 1:

输入:s = ")ebc#da@f("
输出:"(fad@cb#e)"
解释:
字符串中的字母为 ['e', 'b', 'c', 'd', 'a', 'f']:
- 反转后为 ['f', 'a', 'd', 'c', 'b', 'e']
- s 变为 ")fad#cb@e("

字符串中的特殊字符为 [')', '#', '@', '(']:
- 反转后为 ['(', '@', '#', ')']
- s 变为 "(fad@cb#e)"

示例 2:

输入:s = "z"
输出:"z"
解释:
字符串只包含一个字母,反转不改变字符串。没有特殊字符。

示例 3:

输入:s = "!@#$%^&*()"
输出:")(*&^%$#@!"
解释:
字符串不包含字母。字符串包含所有特殊字符,所以反转特殊字符就是反转整个字符串。

提示:

  • 1 <= s.length <= 100
  • s 只由小写英文字母和特殊字符 "!@#$%^&*()" 组成。

解题思路

这道题需要分别对字母和特殊字符进行反转操作,可以使用双指针方法来解决。

核心思路:

  1. 首先将字符串转换为字符数组,便于修改
  2. 使用双指针分别处理字母和特殊字符的反转:
    • 对于字母反转:左指针从头开始,右指针从尾开始,只处理字母位置,跳过特殊字符
    • 对于特殊字符反转:同样使用双指针,只处理特殊字符位置,跳过字母

算法步骤:

  1. 第一轮双指针遍历:反转所有字母
    • 左指针向右移动直到遇到字母
    • 右指针向左移动直到遇到字母
    • 交换两个位置的字母,继续移动指针
  2. 第二轮双指针遍历:反转所有特殊字符
    • 左指针向右移动直到遇到特殊字符
    • 右指针向左移动直到遇到特殊字符
    • 交换两个位置的特殊字符,继续移动指针

这种方法的优势是只需要遍历字符串两次,时间效率高,且逻辑清晰易懂。

推荐解法: 双指针方法,因为它直观、高效,符合题目提示。

代码实现

class Solution {
public:
    string reverseByType(string s) {
        vector<char> chars(s.begin(), s.end());
        int n = chars.size();
        
        // 反转字母
        int left = 0, right = n - 1;
        while (left < right) {
            while (left < right && !isalpha(chars[left])) left++;
            while (left < right && !isalpha(chars[right])) right--;
            if (left < right) {
                swap(chars[left], chars[right]);
                left++;
                right--;
            }
        }
        
        // 反转特殊字符
        left = 0;
        right = n - 1;
        while (left < right) {
            while (left < right && isalpha(chars[left])) left++;
            while (left < right && isalpha(chars[right])) right--;
            if (left < right) {
                swap(chars[left], chars[right]);
                left++;
                right--;
            }
        }
        
        return string(chars.begin(), chars.end());
    }
};
class Solution:
    def reverseByType(self, s: str) -> str:
        chars = list(s)
        n = len(chars)
        
        # 反转字母
        left, right = 0, n - 1
        while left < right:
            while left < right and not chars[left].isalpha():
                left += 1
            while left < right and not chars[right].isalpha():
                right -= 1
            if left < right:
                chars[left], chars[right] = chars[right], chars[left]
                left += 1
                right -= 1
        
        # 反转特殊字符
        left, right = 0, n - 1
        while left < right:
            while left < right and chars[left].isalpha():
                left += 1
            while left < right and chars[right].isalpha():
                right -= 1
            if left < right:
                chars[left], chars[right] = chars[right], chars[left]
                left += 1
                right -= 1
        
        return ''.join(chars)
public class Solution {
    public string ReverseByType(string s) {
        char[] chars = s.ToCharArray();
        int n = chars.Length;
        
        // 反转字母
        int left = 0, right = n - 1;
        while (left < right) {
            while (left < right && !char.IsLetter(chars[left])) left++;
            while (left < right && !char.IsLetter(chars[right])) right--;
            if (left < right) {
                (chars[left], chars[right]) = (chars[right], chars[left]);
                left++;
                right--;
            }
        }
        
        // 反转特殊字符
        left = 0;
        right = n - 1;
        while (left < right) {
            while (left < right && char.IsLetter(chars[left])) left++;
            while (left < right && char.IsLetter(chars[right])) right--;
            if (left < right) {
                (chars[left], chars[right]) = (chars[right], chars[left]);
                left++;
                right--;
            }
        }
        
        return new string(chars);
    }
}
var reverseByType = function(s) {
    const chars = s.split('');
    const n = chars.length;
    
    // 反转字母
    let left = 0, right = n - 1;
    while (left < right) {
        while (left < right && !/[a-z]/.test(chars[left])) left++;
        while (left < right && !/[a-z]/.test(chars[right])) right--;
        if (left < right) {
            [chars[left], chars[right]] = [chars[right], chars[left]];
            left++;
            right--;
        }
    }
    
    // 反转特殊字符
    left = 0;
    right = n - 1;
    while (left < right) {
        while (left < right && /[a-z]/.test(chars[left])) left++;
        while (left < right && /[a-z]/.test(chars[right])) right--;
        if (left < right) {
            [chars[left], chars[right]] = [chars[right], chars[left]];
            left++;
            right--;
        }
    }
    
    return chars.join('');
};

复杂度分析

复杂度类型复杂度说明
时间复杂度O(n)需要遍历字符串两次,每次都是 O(n)
空间复杂度O(n)需要额外的字符数组来存储结果

相关题目