题目描述

✅ 917. 仅仅反转字母

image-20260929105108908

image-20260929105109287

题意分析

只反转字符串中英文字母出现的顺序,数字、标点等非字母仍留在原下标。大小写属于字母本身,移动时不做转换;题目输入只包含 ASCII 字符。

解法:字符副本 + 双指针

核心思路

[!blue]

如果把所有字母单独取出,目标就是反转这个字母序列,再放回原来的字母位置。无需真正建立这个中间序列,只要每次交换尚未处理的第一个和最后一个字母,就能直接完成同样的配对。

先把字符串转成可修改的字符或字节数组,用 l、r 从两端向内移动。左边遇到非字母就只移动 l,右边遇到非字母就只移动 r;两边都停在字母上时交换它们,然后同时向内一步。

每次交换都把待处理字母序列的两端放到最终位置,区间外的字母不再改动,而非字母从未参与交换,始终留在原位。指针相遇时最多剩一个中间字母,本来就无需移动;若只剩非字母,跳过后也会相遇。因此处理到 l >= r 就能结束。

解题步骤

  1. 转换为字符或字节数组,指针放在两端。
  2. 分别跳过非字母,跳过时检查指针尚未相遇。
  3. 交换两侧字母,再同时向内移动。
  4. 返回数组构成的字符串。

代码实现

class Solution {
    public String reverseOnlyLetters(String s) {
        char[] a = s.toCharArray();
        int l = 0;
        int r = a.length - 1;

        while (l < r) {
            // 非字母只跳过不交换,原位置保持不变。
            while (l < r && !Character.isLetter(a[l])) {
                l++;
            }

            while (l < r && !Character.isLetter(a[r])) {
                r--;
            }

            if (l < r) {
                char tmp = a[l];

                a[l] = a[r];
                a[r] = tmp;
                l++;
                r--;
            }
        }

        return new String(a);
    }
}
func reverseOnlyLetters(s string) string {
    a := []byte(s)
    l, r := 0, len(a)-1
    for l < r {
        // 非字母只跳过不交换,原位置保持不变。
        for l < r && !isLetter(a[l]) {
            l++
        }
        for l < r && !isLetter(a[r]) {
            r--
        }
        if l < r {
            a[l], a[r] = a[r], a[l]
            l++
            r--
        }
    }
    return string(a)
}

func isLetter(c byte) bool {
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}

复杂度分析

  • 时间复杂度:$O(n)$,两端指针只向中间移动。
  • 空间复杂度:$O(n)$,保存可修改数组和结果字符串。

关键点总结

[!green]

  • 移动的是字母内容,非字母下标固定。
  • 大小写属于字符自身,不做转换。
  • 跳过非字母时也要检查边界。

易错点总结

[!yellow]

  • 反转整个数组:非字母会移动位置。
  • 只识别小写字母:大写字母被错误保留在原位。
  • 把数字也当作字母:数字位置不再保持。
  • 跳过非字母时不检查边界:全非字母字符串可能越界。

相似题目

题目 难度 关联与区别
345. 反转字符串中的元音字母 简单 同样跳过不参与反转的位置,原题仅反转元音,本题反转所有字母。
344. 反转字符串 简单 普通区间反转的双指针可复用,本题在交换前多一步字符类别筛选。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2022/19927616
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!