Reverse Vowels of a String
EasyPrompt
Given a string s, reverse only all the vowels in the string and return it.
The vowels are 'a', 'e', 'i', 'o', and 'u', and they can appear in both lower and upper cases, more than once.
Example 1:
Input: s = "IceCreAm"
Output: "AceCreIm"
Explanation:
The vowels in s are ['I', 'e', 'e', 'A']. On reversing the vowels, s becomes "AceCreIm".
Example 2:
Input: s = "leetcode"
Output: "leotcede"
Constraints:
1 <= s.length <= 3 * 105sconsist of printable ASCII characters.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach involves two separate passes over the string. The first pass collects all the vowels into a separate data structure. The second pass constructs a new string, replacing the original vowel positions with the collected vowels in reverse order.
Algorithm
- Create a helper data structure (like a
ListorStringBuilder) to store vowels. - Iterate through the input string
sand add every vowel encountered to the helper structure. - Reverse the collection of vowels.
- Create a
StringBuilderfor the result. - Iterate through the input string
sagain. For each character:- If the character is a consonant, append it to the result.
- If the character is a vowel, append the next vowel from the reversed vowel collection to the result.
- Return the final string from the
StringBuilder.
Walkthrough
The core idea is to first isolate the vowels from the string, reverse them, and then place them back into the positions where vowels originally appeared.
Algorithm:
- Create a list or a string to store all the vowels from the input string
s. - Iterate through
sfrom beginning to end. If a character is a vowel, add it to our vowel collection. - After the first pass, our collection contains all vowels in their original order (e.g., for 'IceCreAm', we get ['I', 'e', 'e', 'A']).
- Now, create a
StringBuilderto build the final result. - Initialize a pointer to the end of our vowel collection.
- Iterate through the original string
sagain. If the character at the current position is a vowel, append the vowel from our collection (using the pointer) to theStringBuilderand move the pointer backward. If it's a consonant, append the original character. - Finally, convert the
StringBuilderto a string.
Code Snippet:
class Solution { public String reverseVowels(String s) { // Helper to check if a character is a vowel String vowels = "aeiouAEIOU"; // 1. Collect all vowels from the string StringBuilder vowelCollector = new StringBuilder(); for (char c : s.toCharArray()) { if (vowels.indexOf(c) != -1) { vowelCollector.append(c); } } // 2. Reverse the collected vowels vowelCollector.reverse(); // 3. Build the result string StringBuilder result = new StringBuilder(); int vowelIndex = 0; for (char c : s.toCharArray()) { if (vowels.indexOf(c) != -1) { result.append(vowelCollector.charAt(vowelIndex)); vowelIndex++; } else { result.append(c); } } return result.toString(); }}Complexity
Time
O(N), where N is the length of the string. We make two full passes over the string: one to collect vowels and another to build the result string. Each pass takes O(N) time.
Space
O(N). We use extra space for storing the vowels (O(K), where K is the number of vowels) and for the `StringBuilder` to construct the final string (O(N)). In the worst case, where all characters are vowels, this becomes O(N).
Trade-offs
Pros
Simple to understand and implement.
Clearly separates the concerns of finding vowels and reconstructing the string.
Cons
Less efficient due to two passes over the string.
Requires extra space proportional to the number of vowels and the length of the string.
A more efficient, in-place approach that uses two pointers to swap vowels. One pointer starts from the beginning of the string and another from the end. They move towards each other, swapping vowels as they find them.
Algorithm
- Convert the input string
sto a character arraychars. - Initialize two pointers,
left = 0andright = s.length() - 1. - Loop while
left < right:- Increment
leftuntilchars[left]is a vowel. - Decrement
rightuntilchars[right]is a vowel. - If
left < right, swapchars[left]andchars[right]. - Increment
leftand decrementright.
- Increment
- Convert the
charsarray back to a string and return it.
Walkthrough
This method avoids the need for extra storage for vowels by performing swaps directly on a character array representation of the string. It uses a single pass where two pointers converge.
Algorithm:
- Convert the input string
sto a character array,chars, since strings are immutable in Java. - Initialize a
leftpointer to0and arightpointer tos.length() - 1. - Use a
whileloop to continue as long asleft < right. - Inside the loop, move the
leftpointer forward until it points to a vowel. - Move the
rightpointer backward until it points to a vowel. - If
leftis still less thanright, it means we have found a pair of vowels. Swap the characters atchars[left]andchars[right]. - After the swap, increment
leftand decrementrightto continue the search for the next pair. - Once the loop finishes (when
left >= right), convert the modified character array back into a string and return it.
To efficiently check for vowels, a Set can be used for O(1) lookups.
Code Snippet:
import java.util.Arrays;import java.util.HashSet;import java.util.Set; class Solution { public String reverseVowels(String s) { Set<Character> vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U')); char[] chars = s.toCharArray(); int left = 0; int right = s.length() - 1; while (left < right) { // Find the first vowel from the left while (left < right && !vowels.contains(chars[left])) { left++; } // Find the first vowel from the right while (left < right && !vowels.contains(chars[right])) { right--; } // Swap the vowels if (left < right) { char temp = chars[left]; chars[left] = chars[right]; chars[right] = temp; // Move pointers inward left++; right--; } } return new String(chars); }}Complexity
Time
O(N), where N is the length of the string. The `left` and `right` pointers each traverse the array at most once, resulting in a single-pass algorithm.
Space
O(N). In Java, strings are immutable, so we must convert the string to a character array, which requires O(N) space. In languages with mutable strings, the space complexity would be O(1) (excluding the space for the vowel set, which is constant).
Trade-offs
Pros
More efficient as it requires only a single pass over the data.
Considered an in-place algorithm conceptually, though Java's string immutability requires an auxiliary character array.
Lower constant factor for space usage compared to the two-pass approach.
Cons
The logic can be slightly more complex to write correctly compared to the two-pass approach.
Solutions
Solution
class Solution {public String reverseVowels(String s) { boolean[] vowels = new boolean[128]; for (char c : "aeiouAEIOU".toCharArray()) { vowels[c] = true; } char[] cs = s.toCharArray(); int i = 0, j = cs.length - 1; while (i < j) { while (i < j && !vowels[cs[i]]) { ++i; } while (i < j && !vowels[cs[j]]) { --j; } if (i < j) { char t = cs[i]; cs[i] = cs[j]; cs[j] = t; ++i; --j; } } return String.valueOf(cs); }}class Solution {public: string reverseVowels(string s) { bool vowels[128]; memset(vowels, false, sizeof(vowels)); for (char c : "aeiouAEIOU") { vowels[c] = true; } int i = 0, j = s.size() - 1; while (i < j) { while (i < j && !vowels[s[i]]) { ++i; } while (i < j && !vowels[s[j]]) { --j; } if (i < j) { swap(s[i++], s[j--]); } } return s; }};class Solution: # class Solution : def reverseVowels ( self , s : str ) -> str : vowels = "aeiouAEIOU" # or, vowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'} i , j = 0 , len ( s ) - 1 cs = list ( s ) while i < j : while i < j and cs [ i ] not in vowels : i += 1 while i < j and cs [ j ] not in vowels : j -= 1 if i < j : cs [ i ], cs [ j ] = cs [ j ], cs [ i ] i , j = i + 1 , j - 1 return "" . join ( cs ) def reverseVowels(self, s: str) -> str: vowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'} i, j = 0, len(s) - 1 chars = list(s) while i < j: if chars[i] not in vowels: i += 1 elif chars[j] not in vowels: j -= 1 else: chars[i], chars[j] = chars[j], chars[i] i += 1 j -= 1 return '' . join(chars)Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.