Mastering LeetCode Problem 0345
Problem 0345: Reverse Vowels of a String
When solving string problems on LeetCode, you’ll notice a recurring pattern:
two pointers moving towards each other from the ends of the string.
LeetCode 345 – Reverse Vowels of a String – is a beautiful, focused exercise on this pattern.
It’s simpler than many “two-pointer” problems, yet rich enough to train your intuition for more advanced challenges.
In this post, we’ll break down the problem, discuss naive and optimal ideas, and then walk step-by-step through an elegant two-pointer solution—aligned with the exact logic you implemented.
1. Problem Statement
You are given a string s.
Your task is to reverse only the vowels in the string and return the resulting string.
- Vowels are:
a, e, i, o, u, A, E, I, O, U - Consonants, digits, and symbols must stay in their original positions.
- You only change the positions of vowels, by reversing their order.
1.1. Example 1
Input: s = "hello"
Output: "holle"
Vowels: 'e' and 'o'
Reversing them: "holle"
1.2. Example 2
Input: s = "leetcode"
Output: "leotcede"
Vowels in order: e, e, o, e
Reversed vowels: e, o, e, e
Final string: "leotcede"
Example 3
Input: s = "IceCreAm"
Output: "AceCreIm"
Vowels (in order): I, e, e, A
Reversed: A, e, e, I
Consonants remain in place; only vowels are reordered.
2. First Thoughts – A Straightforward (But Less Elegant) Approach
The most direct idea might look like this:
- Traverse the string and collect all vowels in a list.
- Reverse that list of vowels.
- Traverse the string again:
- Every time you see a vowel, replace it with the next vowel from the reversed list.
This works.
But what are the costs?
- You make multiple passes over the string.
- You maintain a list of all vowels.
- There’s extra management for indices into that reversed list.
Time complexity is still O(n) and space complexity is also O(n), but the solution feels less direct and less “in-place”.
This is fine as a first attempt. However, there’s a cleaner and more “interview-friendly” pattern we can apply.
3. The Two-Pointer Idea
Two-pointer problems on strings or arrays usually come in one of these flavors:
- Same direction: both pointers move forward (e.g., slow & fast pointer).
- Opposite directions: one pointer from the start, one from the end.
This problem is clearly in the second category.
Here’s the high-level idea:
- Convert the string to a mutable list of characters (since Python strings are immutable).
- Maintain two indices:
-
leftstarting at the beginning (0) -
rightstarting at the end (len(s) - 1)
-
- While
left < right:- Move
leftto the right until it lands on a vowel. - Move
rightto the left until it lands on a vowel. - If both
s[left]ands[right]are vowels:- Swap them.
- Move both pointers inward.
- Move
By doing this, we effectively reverse only the vowels while leaving all other characters untouched.
This gives us:
- Single pass with two pointers → O(n) time.
- Only a list conversion overhead → O(n) space (standard for in-place swaps in Python).
4. Implementation – Two Pointers, In-Place on a List
Let’s look at the core logic in Python, matching the algorithm you implemented.
Note: For LeetCode’s expected signature, you’d add
selfas the first parameter, but here we focus on the core idea.
class Solution:
def reverseVowels(s: str) -> str:
vowels = set("aeiouAEIOU")
s = list(s)
left, right = 0, len(s) - 1
while left < right:
if s[left] not in vowels:
left += 1
continue
if s[right] not in vowels:
right -= 1
continue
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
return "".join(s)
We’ll now dissect this line by line.
5. Detailed Walkthrough
5.1. Defining the Vowel Set and Converting String to List
vowels = set("aeiouAEIOU")
s = list(s)
-
vowelsis asetof characters for O(1) lookup. - Both lowercase and uppercase vowels are covered.
-
s = list(s)converts the string to a list of characters so we can swap in-place.
5.2. Initializing the Two Pointers
left, right = 0, len(s) - 1
-
leftstarts from the beginning. -
rightstarts from the end.
We will process the string from both ends towards the middle.
5.3. Main Loop
while left < right:
We continue as long as left is strictly less than right.
When left >= right, all needed swaps are done.
Inside this loop, we have three key components.
5.3.1. Move left Until It Reaches a Vowel
if s[left] not in vowels:
left += 1
continue
- If
s[left]is not a vowel:- Increment
leftand skip the rest of this iteration (continue).
- Increment
- This effectively means:
- “Keep moving
leftforward until you find a vowel.”
- “Keep moving
5.3.2. Move right Until It Reaches a Vowel
if s[right] not in vowels:
right -= 1
continue
- If
s[right]is not a vowel:- Decrement
rightand skip the rest of this iteration.
- Decrement
- Interpretation:
- “Keep moving
rightbackward until you find a vowel.”
- “Keep moving
5.3.3. Swap the Two Vowels
If we reach this part, it means:
-
s[left]is a vowel. -
s[right]is a vowel.
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
We:
- Swap the two vowels.
- Move
leftforward andrightbackward for the next pair.
After enough iterations, we have reversed the order of vowels in the string.
6. Example Walkthrough: "IceCreAm"
Let’s trace your implementation on the example:
Input: "IceCreAm"
Initial setup:
s = ['I', 'c', 'e', 'C', 'r', 'e', 'A', 'm']
left = 0
right = 7
6.1. Iteration 1
-
s[left] = 'I'→ vowel -
s[right] = 'm'→ not vowel →right -= 1→right = 6
6.2. Iteration 2
-
left = 0,right = 6 -
s[left] = 'I'→ vowel -
s[right] = 'A'→ vowel - Swap:
s[0], s[6] = s[6], s[0] # 'I' <-> 'A'
Now:
s = ['A', 'c', 'e', 'C', 'r', 'e', 'I', 'm']
left = 1
right = 5
6.3. Iteration 3
-
s[1] = 'c'→ not vowel →left = 2 -
s[2] = 'e'→ vowel -
s[5] = 'e'→ vowel - Swap
s[2]ands[5]:- Both are ‘e’, so string stays the same.
- Move pointers:
left = 3
right = 4
6.4. Iteration 4
-
s[3] = 'C'→ not vowel →left = 4 - Now
left = 4,right = 4→ loop conditionleft < rightfails.
End of loop.
Final s:
['A', 'c', 'e', 'C', 'r', 'e', 'I', 'm']
Return:
"AceCreIm"
All vowels have been reversed while consonants stayed exactly where they were.
7. Time and Space Complexity
7.1. Time Complexity
- Each pointer (
leftandright) moves at mostnsteps. - In each iteration, we do constant work:
- Comparisons,
- Pointer increments/decrements,
- Occasional swap.
Therefore:
$\text{Time Complexity} = O(n)$
where ( n = \text{len}(s) ).
7.2. Space Complexity
- Converting the string to a list uses O(n) extra space.
- The
vowelsset is constant-sized: O(1).
So:
$\text{Space Complexity} = O(n)$
In Python, this is a very standard and acceptable approach for in-place modification of strings.
8. Edge Cases and How This Approach Handles Them
Let’s check some edge cases.
8.1. No Vowels
s = "bcdfg"
- Both pointers move inward, but never find vowels to swap.
- The string remains unchanged.
- Our code behaves correctly.
8.2. All Vowels
s = "aeiou"
-
leftat ‘a’,rightat ‘u’ → swap → ‘u’, ‘e’, ‘i’, ‘o’, ‘a’ - Then
leftandrightmove inward and swap ‘e’ and ‘o’. - Final result:
"uoiea"→ vowels fully reversed.
8.3. Single Character
s = "a" or s = "b"
-
left = 0,right = 0 -
left < rightis false from the start. - We immediately return the string.
8.4. Empty String
s = ""
-
left = 0,right = -1 - Loop never executes.
- Returns the empty string.
8.5. Mix of Uppercase and Lowercase
Because our vowel set includes both lowercase and uppercase (aeiouAEIOU), cases like:
s = "AeIoU"
are also correctly handled.
9. Pattern Recognition – Why This Problem Matters
This problem is more than just vowel reversal. It trains a reusable mental template:
Two pointers moving from both ends, skipping irrelevant characters, and acting only on a specific subset.
You’ve already seen very similar ideas in:
- LeetCode 125 – Valid Palindrome
- Two pointers, skip non-alphanumeric characters, compare remaining ones.
- LeetCode 344 – Reverse String
- Two pointers, swap characters directly from both ends.
- LeetCode 345 – Reverse Vowels of a String
- Two pointers, but operate only when both sides land on vowels.
The core insight:
- Filter & act pattern:
- Skip non-target characters.
- Apply logic when both sides are “interesting” (e.g., vowel, alphanumeric).
- This generalizes to many string-processing questions.