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^5s由可打印 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)class Solution {
public String reverseVowels(String s) {
String vowels = "aeiouAEIOU";
char[] t = s.toCharArray();
int i = 0, j = t.length - 1;
while (i < j) {
if (vowels.indexOf(t[i]) < 0) {
i++;
} else if (vowels.indexOf(t[j]) < 0) {
j--;
} else {
char c = t[i]; t[i] = t[j]; t[j] = c;
i++;
j--;
}
}
return new String(t);
}
}class Solution {
public:
string reverseVowels(string s) {
string vowels = "aeiouAEIOU";
string t = s;
int i = 0, j = (int)t.size() - 1;
while (i < j) {
if (vowels.find(t[i]) == string::npos) {
i++;
} else if (vowels.find(t[j]) == string::npos) {
j--;
} else {
swap(t[i], t[j]);
i++;
j--;
}
}
return t;
}
};func reverseVowels(s string) string {
vowels := "aeiouAEIOU"
t := []byte(s)
i, j := 0, len(t)-1
for i < j {
if !strings.ContainsRune(vowels, rune(t[i])) {
i++
} else if !strings.ContainsRune(vowels, rune(t[j])) {
j--
} else {
t[i], t[j] = t[j], t[i]
i++
j--
}
}
return string(t)
}var reverseVowels = function(s) {
const vowels = new Set('aeiouAEIOU');
const t = s.split('');
let i = 0, j = t.length - 1;
while (i < j) {
if (!vowels.has(t[i])) {
i++;
} else if (!vowels.has(t[j])) {
j--;
} else {
[t[i], t[j]] = [t[j], t[i]];
i++;
j--;
}
}
return t.join('');
};function reverseVowels(s: string): string {
const vowels = new Set('aeiouAEIOU');
const t = s.split('');
let i = 0, j = t.length - 1;
while (i < j) {
if (!vowels.has(t[i])) {
i++;
} else if (!vowels.has(t[j])) {
j--;
} else {
[t[i], t[j]] = [t[j], t[i]];
i++;
j--;
}
}
return t.join('');
}