leetcode- 仅仅反转字母

197 阅读2分钟

「这是我参与2022首次更文挑战的第36天,活动详情查看:2022首次更文挑战」。

题目

给你一个字符串 s ,根据下述规则反转字符串:
所有非英文字母保留在原有位置。
所有英文字母(小写或大写)位置反转。
返回反转后的 s 。

示例 1:
输入:s = "ab-cd"
输出:"dc-ba"

示例 2:
输入:s = "a-bC-dEf-ghIj"
输出:"j-Ih-gfE-dCba"

示例 3:
输入:"Test1ng-Leet=code-Q!"
输出:"Qedo1ct-eeLg=ntse-T!"

思路

直观

一拿到这个题目,想到的直观思路是这样的:

  1. 遍历原始字符串,获取出英文字母,加入新的中间字符串snew
  2. 反转中间字符串snew,形成sre
  3. 遍历原始字符串,如果该位置不是英文字母,保持不变;如果是英文字母,从sre中获取当前指针指向的字符,指针从0开始,获取一次就向后走一步

我们用示例1的输入来走一遍:

  1. 遍历s,取出英文字母,形成snew = "abcd"
  2. 反转abcd,形成sre = "dcba" 直观0.png
  3. 遍历原始字符串:
  • 第0位是a,是英文字母,所以从sre中获取字符,当前指针指向d 直观1.png
  • 第1位是b,是英文字母,所以从sre中获取字符,当前指针指向c

直观2.png

  • 第2位是-,不是英文字母,所以保持不变

直观3.png

  • 第3位是c,是英文字母,所以从sre中获取字符,当前指针指向b

直观4.png

  • 第4位是d,是英文字母,所以从sre中获取字符,当前指针指向a

直观5.png 综上,结果字符串是"dc-ba"

双指针

看了题解,发现也可以用双指针来解决:

  1. 指针left和right分别指向s的头和尾
  2. left向右移动,直到找到第1个英文字母
  3. right向左移动,直到找到第1个英文字母
  4. 交换s[left]和s[right]
  5. 重复2-4步,直到left >= right

Java版本代码

class Solution {
    public String reverseOnlyLetters(String s) {
        int left = 0;
        int right = s.length()-1;
        char[] arr = s.toCharArray();
        while (left < right) {
            while (left < right && !Character.isLetter(arr[left])) {
                left++;
            }
            while (left < right && !Character.isLetter(arr[right])) {
                right--;
            }
            if (left < right) {
                char temp = arr[left];
                arr[left] = arr[right];
                arr[right] = temp;
                left++;
                right--;
            }
        }
        return new String(arr);
    }
}