17370845950

LeetCode 反转字符串中的元音字母:正确实现双指针与字符处理技巧

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

你的原始代码逻辑方向基本正确——识别元音、记录位置与字符、再反向填充——但存在三个关键缺陷,导致 'hello' 无法输出 'holle':

  1. count 变量误用:在第二轮遍历中,count++ 被放在 for 循环体顶层,导致它每轮都自增,而非仅在匹配到目标索引时才推进。结果是 markedItemsIndex[count] 很快越界或错位,if (i === markedItemsIndex[count]) 几乎永不成立(因此 'here' 不打印)。

  2. 元音判定不完整:只检查了小写 a, i, u, e, o,而题目要求区分大小写无关(如 'Hello' 应输出 'Holle')。硬编码多个 === 条件既冗长又易漏,应使用正则 /[aeiou]/i(i 标志启用忽略大小写匹配)。

  3. 返回值类型错误:return newString 返回的是字符数组,而题目要求返回字符串。必须调用 .join('')。

✅ 修正后的简洁实现(推荐双指针法,更优时间/空间复杂度):

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

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

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

  return arr.join(''); // ✅ 关键:转回字符串
};

? 为什么双指针更优?

  • 时间复杂度:O(n),仅一次遍历;原方法需两次遍历 + 数组操作,实际也是 O(n),但常数更大。
  • 空间复杂度:O(n)(字符数组),与原方法一致,但无需额外存储索引与元音列表,逻辑更清晰、不易出错。
  • 可读性与健壮性:避免手动维护 count 和索引映射,天然支持大小写,无越界风险。

⚠️ 注意事项总结:

  • 元音集合务必包含大写('A', 'E', ...)或使用 /[aeiou]/i.test(char);
  • 字符串不可变,必须转为数组操作后 join('');
  • 双指针中 while 内需重复检查 left
  • 交换使用解构赋值 [a, b] = [b, a] 简洁安全。

运行 reverseVowels("hello") → "holle",reverseVowels("Hello World!") → "Holle Werld!",完全符合预期。