题目来源:LeetCode345:反转字符串中的元音字母
问题抽象: 给定一个 字符数组 s
(由 ASCII 字符组成),要求 原地反转数组中所有元音字母的位置(非元音字母保持原位),满足以下核心需求:
-
反转规则:
- 元音字母定义:小写
'a','e','i','o','u'
及大写形式(共10
种); - 交换逻辑:首个元音字母与末尾元音字母交换,次个元音字母与次末元音字母交换,依此类推;
- 非元音字母位置不变。
- 元音字母定义:小写
-
操作约束:
- 空间复杂度 O(1):仅允许常数级额外空间(双指针+临时变量);
- 时间复杂度 O(n):单次遍历完成(
n
为数组长度); - 原地修改:直接操作输入数组(无返回值或返回修改后数组)。
-
边界处理:
- 空数组:直接返回;
- 无元音字母:数组保持不变;
- 大小写敏感:
'A'
与'a'
均视为元音,但交换时保留原大小写; - 奇偶元音数量:
- 奇数个元音时中间元音位置不变(如
"hello"
→"holle"
,中间'o'
与自身交换); - 偶数个元音时两两交换(如
"leetcode"
→"leotcede"
)。
- 奇数个元音时中间元音位置不变(如
-
特殊案例:
- 输入
["h","e","l","l","o"]
→ 输出["h","o","l","l","e"]
('e'
与'o'
交换); - 输入
["l","e","e","t","c","o","d","e"]
→ 输出["l","e","o","t","c","e","d","e"]
; - 输入
["b","c","d"]
→ 输出不变(无元音)。
- 输入
输入:字符数组 s
(长度范围 [0, 3×10^5]
)
输出:无返回值(s
修改为元音反转后的数组)。
解题思路
题目要求反转字符串中的元音字母(包括大小写)。采用双指针法实现高效反转:
- 双指针扫描:左指针
left
从头部开始,右指针right
从尾部开始 - 跳过非元音:左右指针各自向中间移动,直到指向元音字母
- 交换元音:当左右指针都指向元音时交换它们
- 继续扫描:交换后左右指针同时向中间移动一位
- 终止条件:当
left >= right
时停止
优化点:
- 使用字符数组直接操作,避免字符串不可变性带来的开销
- 预定义元音集合,使用
String.contains()
快速判断 - 双指针一次遍历完成操作,时间复杂度 O(n),空间复杂度 O(n)
代码实现(Java版)🔥点击下载源码
class Solution {
public String reverseVowels(String s) {
if (s == null || s.isEmpty()) return s;
char[] chars = s.toCharArray();
int left = 0, right = chars.length - 1;
// 元音字母集合(包含大小写)
String vowels = "aeiouAEIOU";
while (left < right) {
// 左指针移动到元音位置
while (left < right && vowels.indexOf(chars[left]) == -1) {
left++;
}
// 右指针移动到元音位置
while (left < right && vowels.indexOf(chars[right]) == -1) {
right--;
}
// 交换两个元音字母
if (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
}
return new String(chars);
}
}
代码说明
- 字符数组转换:
s.toCharArray()
将字符串转为可修改的字符数组 - 双指针初始化:
left=0
从头部开始right=chars.length-1
从尾部开始
- 元音判断:通过
vowels.indexOf(ch) == -1
判断非元音字符 - 指针移动:
- 左指针遇到非元音时
left++
- 右指针遇到非元音时
right--
- 左指针遇到非元音时
- 交换操作:当两指针都指向元音时执行交换,并同步移动指针
- 结果构建:最后通过
new String(chars)
将字符数组转为字符串
复杂度分析:时间复杂度:O(n),双指针完整扫描字符串一次。空间复杂度:O(n),存储字符数组(返回结果必须的空间)