在问 · 算法题解

345. 反转字符串中的元音字母

题目描述

输入一个字符串 s。元音字母指 a、e、i、o、u,大写和小写都算,可能出现多次。

把 s 中所有元音字母的出现顺序整体颠倒,其他字符的位置保持不变。也就是说,第一个元音和最后一个元音互换,第二个和倒数第二个互换,依此类推。

返回处理后的字符串。

示例 1
输入:s = "IceCreAm"
输出:"AceCreIm"

解释:元音依次为 I,e,e,A,倒序后放回原位置得到 "AceCreIm"。

示例 2
输入:s = "leetcode"
输出:"leotcede"

解释:元音依次为 e,e,o,e,倒序为 e,o,e,e。

数据范围

  • 1 <= s.length <= 3 * 10^5
  • s 由可打印 ASCII 字符组成

解题思路

和普通的反转字符串一样用左右两个指针向中间靠拢,只是要跳过非元音:如果 t[i] 不是元音,i 右移;否则如果 t[j] 不是元音,j 左移;两边都是元音时交换,然后两个指针都向中间走一步。左边第 k 个元音总是和右边第 k 个元音交换,这正是元音序列的反转。由于 Python 字符串不可修改,先转成列表 t,最后再拼回字符串。

为什么正确

t[0..i) 和 t(j..n-1] 已经是最终结果;左侧已处理的元音个数始终等于右侧已处理的元音个数。

复杂度分析

时间 O(n):每轮循环至少移动一个指针;额外空间 O(n),用于字符列表(C++ 中可以直接在字符串副本上操作)。

易错点

别忘了大写元音 AEIOU;另外每轮只移动一个指针或交换一次,如果用内层 while 跳过非元音,内层循环也必须带上 i < j 的条件,否则会越界。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def reverseVowels(self, s: str) -> str:
        vowels = set('aeiouAEIOU')
        t = list(s)
        i, j = 0, len(t) - 1
        while i < j:
            if t[i] not in vowels:
                i += 1
            elif t[j] not in vowels:
                j -= 1
            else:
                t[i], t[j] = t[j], t[i]
                i += 1
                j -= 1
        return ''.join(t)

载入编辑器,自己跑一遍 →

双指针 专题的其他题目

查看 双指针 全部题目 →