Pattern: Two Pointers → opposite ends
Difficulty: Easy
Time: O(n) | Space: O(n) for the char array (JS strings are immutable)

Problem

Reverse only the vowels in a string. Everything else stays where it is.
Vowels are a e i o u, upper and lower case.

"IceCreAm" → "AceCreIm"
"leetcode" → "leotcede"

Core idea

One pointer at each end. Each walks inward until it lands on a vowel. Swap, then keep going.

  1. l starts at 0, r at the end.
  2. Move l right until it’s on a vowel.
  3. Move r left until it’s on a vowel.
  4. Swap them, move both inward.
  5. Stop when they meet.

It’s a normal string reverse, except each pointer skips the letters you don’t care about.

Code (TypeScript)

function reverseVowels(s: string): string {
  const vowels = new Set("aeiouAEIOU");
  const chars = s.split(""); // strings can't be changed, arrays can
  let l = 0;
  let r = chars.length - 1;
 
  while (l < r) {
    while (l < r && !vowels.has(chars[l])) l++; // find a vowel from the left
    while (l < r && !vowels.has(chars[r])) r--; // find a vowel from the right
    [chars[l], chars[r]] = [chars[r], chars[l]];
    l++;
    r--;
  }
 
  return chars.join("");
}

Gotchas

  • Uppercase vowels count. "IceCreAm" fails if you only check lowercase.
  • Every inner while needs l < r first, or the pointers can run past each other.
  • A Set lookup is O(1). "aeiou".includes(c) also works and is fine for 10 letters.
  • JS strings are immutable, so s[l] = ... silently does nothing. Split into an array first.
  • Test: no vowels ("bcd"), one letter, all vowels, mixed case.

Cues that said “two pointers”

  • The word reverse → swap position l with position r.
  • Only some items take part → each pointer skips until it finds one.