17370845950

LeetCode 反转字符串中的元音字母:正确实现双指针与字符替换逻辑

本文详解 leetcode「反转元音字母」题目的常见错误与优化解法,重点修复索引错位、大小写遗漏及返回值类型问题,并提供简洁高效的双指针实现方案。

你的原始代码思路清晰——标记元音位置、提取元音字符、倒序填充——但存在三个关键缺陷:

  1. count 变量在循环中无条件递增:导致 markedItemsIndex[count] 很快越界或匹配失败(如 i=0 时 count=1,跳过首个元音);
  2. 未处理大写元音(如 'A', 'E'),使 'Hello' → 'Holle' 失败;
  3. 返回值为数组而非字符串,缺少 .join(''),不符合题目输出要求。

✅ 正确修复方式如下(修正版单次遍历逻辑):

var reverseVowels = function(s) {
  const vowels = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']);
  const chars = s.split('');
  let left = 0, right = chars.length - 1;

  while (left < right) {
    // 从左找元音
    while (left < right && !vowels.has(chars[left])) left++;
    // 从右找元音
    while (left < right && !vowels.has(chars[right])) right--;

    // 交换
    if (left < right) {
      [chars[left], chars[right]] = [chars[right], chars[left]];
      left++;
      right--;
    }
  }

  return chars.join(''); // ✅ 必须转回字符串
};

? 为什么双指针更优?

  • 时间复杂度 O(n),仅需一次遍历;
  • 空间复杂度 O(n)(字符数组),避免额外存储索引与元音数组;
  • 逻辑直观:两端向中间收缩,直接交换,无需标记/重排/计数等易错步骤。

⚠️ 注意事项:

  • 使用 Set 判断元音比链式 || 或正则 /[aeiou]/i.test() 更高效(尤其在长字符串中);
  • vowels.has() 区分大小写,因此显式加入大写字母(比正则更语义明确且性能略优);
  • 交换后必须同时移动 left 和 right,否则陷入死循环。

运行示例:
reverseVowels("hello") → ['h','e','l','l','o'] → ['h','o','l','l','e'] → "holle" ✅
reverseVowels("Hello World!") → "Holle Werld!" ✅('e'↔'o', 'o'↔'e', '!' 非元音不参与)

总结:避免用“标记-收集-倒序填充”这类多阶段模拟逻辑,优先采用原地双指针交换——结构简洁、边界清晰、容错性强,是处理此类对称替换问题的标准范式。