1119. Remove Vowels from a String 🔒
Problem Description
Given a string s
, you need to remove all lowercase vowels from it. The vowels to be removed are: 'a'
, 'e'
, 'i'
, 'o'
, and 'u'
. Return the new string after removing these vowels.
The solution iterates through each character in the input string s
. For each character c
, it checks whether the character is a vowel by testing if c
is in the string "aeiou"
. If the character is not a vowel, it gets included in the result. The join()
method combines all non-vowel characters into the final string.
For example:
- Input:
"leetcode"
→ Output:"ltcd"
(removes 'e', 'e', 'o', 'e') - Input:
"aeiou"
→ Output:""
(removes all characters since they're all vowels) - Input:
"xyz"
→ Output:"xyz"
(no vowels to remove)
The time complexity is O(n)
where n
is the length of the string, as we traverse the string once. The space complexity is O(n)
for storing the result string.
Intuition
The problem asks us to filter out specific characters from a string. When we need to keep only certain characters or exclude certain characters from a string, the most straightforward approach is to examine each character individually and decide whether to keep it or discard it.
Since we need to remove vowels, we can think of this as building a new string that contains everything except vowels. For each character in the original string, we ask: "Is this a vowel?" If it's not a vowel, we keep it; if it is a vowel, we skip it.
The key insight is that checking membership in a small set of characters (the five vowels) is a constant-time operation. We can use the expression c not in "aeiou"
to quickly determine if a character should be kept. This leads us naturally to a list comprehension or generator expression that filters the string.
The pattern "".join(c for c in s if condition)
is a Python idiom for string filtering - we generate all characters that meet our condition and then join them back into a string. This approach is both readable and efficient, as it processes the string in a single pass without needing explicit loops or temporary lists for accumulation.
Solution Approach
The solution uses a simulation approach where we traverse the string character by character and build a new string containing only non-vowel characters.
The implementation consists of three key components:
-
Character Traversal: We iterate through each character
c
in the input strings
using a generator expressionfor c in s
. -
Vowel Check: For each character, we check if it's a vowel using the condition
c not in "aeiou"
. This leverages Python'sin
operator to check membership in a string, which treats the string as a collection of characters. The check happens in constant time since we're checking against a fixed set of 5 characters. -
String Building: We use
"".join()
to efficiently concatenate all the non-vowel characters. The generator expression(c for c in s if c not in "aeiou")
produces only the characters that pass our vowel check, andjoin()
combines them into the final result string.
The complete implementation in one line:
return "".join(c for c in s if c not in "aeiou")
This approach processes each character exactly once, making it optimal in terms of time complexity. The algorithm doesn't require any additional data structures beyond the result string being built, keeping the implementation clean and memory-efficient.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the input string "hello"
.
Step 1: Initialize traversal
- Input string:
"hello"
- We'll examine each character and decide whether to keep it
Step 2: Process each character
- Character
'h'
: Check if'h'
is in"aeiou"
→ No, it's not a vowel → Keep it - Character
'e'
: Check if'e'
is in"aeiou"
→ Yes, it's a vowel → Skip it - Character
'l'
: Check if'l'
is in"aeiou"
→ No, it's not a vowel → Keep it - Character
'l'
: Check if'l'
is in"aeiou"
→ No, it's not a vowel → Keep it - Character
'o'
: Check if'o'
is in"aeiou"
→ Yes, it's a vowel → Skip it
Step 3: Build result
- Characters to keep:
'h'
,'l'
,'l'
- Join them together:
"hll"
Final Result: "hll"
The solution processes this in one line:
"".join(c for c in "hello" if c not in "aeiou")
The generator expression produces: 'h'
→ 'l'
→ 'l'
, which are then joined into "hll"
.
Solution Implementation
1class Solution:
2 def removeVowels(self, s: str) -> str:
3 """
4 Remove all lowercase vowels from the input string.
5
6 Args:
7 s: Input string containing lowercase English letters
8
9 Returns:
10 String with all vowels (a, e, i, o, u) removed
11 """
12 # Define the set of vowels to be removed
13 vowels = "aeiou"
14
15 # Iterate through each character and keep only non-vowels
16 # Using list comprehension with join for efficient string building
17 return "".join(c for c in s if c not in vowels)
18
1class Solution {
2 /**
3 * Removes all lowercase vowels from the input string.
4 *
5 * @param s the input string to process
6 * @return a new string with all lowercase vowels removed
7 */
8 public String removeVowels(String s) {
9 // Use StringBuilder for efficient string concatenation
10 StringBuilder result = new StringBuilder();
11
12 // Iterate through each character in the input string
13 for (int i = 0; i < s.length(); i++) {
14 char currentChar = s.charAt(i);
15
16 // Check if the current character is NOT a lowercase vowel
17 if (!isVowel(currentChar)) {
18 // Append non-vowel characters to the result
19 result.append(currentChar);
20 }
21 }
22
23 // Convert StringBuilder to String and return
24 return result.toString();
25 }
26
27 /**
28 * Helper method to check if a character is a lowercase vowel.
29 *
30 * @param c the character to check
31 * @return true if the character is a lowercase vowel, false otherwise
32 */
33 private boolean isVowel(char c) {
34 return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
35 }
36}
37
1class Solution {
2public:
3 string removeVowels(string s) {
4 // Initialize result string to store consonants
5 string result;
6
7 // Iterate through each character in the input string
8 for (const char& ch : s) {
9 // Check if current character is not a vowel
10 if (ch != 'a' && ch != 'e' && ch != 'i' && ch != 'o' && ch != 'u') {
11 // Append consonant to result string
12 result += ch;
13 }
14 }
15
16 // Return the string with vowels removed
17 return result;
18 }
19};
20
1/**
2 * Removes all lowercase vowels from the input string
3 * @param s - The input string to process
4 * @returns A new string with all lowercase vowels (a, e, i, o, u) removed
5 */
6function removeVowels(s: string): string {
7 // Use regular expression to match all lowercase vowels globally and replace with empty string
8 return s.replace(/[aeiou]/g, '');
9}
10
Time and Space Complexity
Time Complexity: O(n)
, where n
is the length of the input string s
. The algorithm iterates through each character in the string exactly once to check if it's a vowel, and the membership check c not in "aeiou"
takes O(1)
time since the vowel string has a fixed size of 5. Therefore, the overall time complexity is linear with respect to the input size.
Space Complexity: O(n)
for the output string. While the reference answer states O(1)
when ignoring the space consumption of the answer, if we consider the space needed to store the result, it's O(n)
in the worst case (when the input contains no vowels). The generator expression itself uses O(1)
auxiliary space as it processes characters one at a time, but the join()
method creates a new string to store the result, which requires space proportional to the number of non-vowel characters in the input.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Not Handling Mixed Case Characters
The current solution only removes lowercase vowels ('a', 'e', 'i', 'o', 'u'). If the input string contains uppercase vowels ('A', 'E', 'I', 'O', 'U'), they will remain in the output string.
Example of the issue:
- Input:
"LeetCode"
→ Output:"LtCd"
(keeps 'L' and 'C') - But if uppercase vowels should also be removed:
"AEIOUaeiou"
→ Current output:"AEIOU"
, Expected:""
Solution:
def removeVowels(self, s: str) -> str:
vowels = "aeiouAEIOU" # Include both cases
return "".join(c for c in s if c not in vowels)
2. Using String Concatenation Instead of Join
A common mistake is building the result string using repeated concatenation with the +
operator:
Inefficient approach:
def removeVowels(self, s: str) -> str:
result = ""
for c in s:
if c not in "aeiou":
result += c # String concatenation creates new string each time
return result
This approach has O(n²) time complexity in the worst case because strings are immutable in Python, and each concatenation creates a new string object.
Better solution: Use the join()
method as shown in the original solution, or use a list to collect characters:
def removeVowels(self, s: str) -> str:
result = []
for c in s:
if c not in "aeiou":
result.append(c)
return "".join(result)
3. Using a Set vs String for Vowel Lookup
While using "aeiou"
works fine for this small set, some might think using a set would be more efficient:
def removeVowels(self, s: str) -> str:
vowels = {'a', 'e', 'i', 'o', 'u'} # Using a set
return "".join(c for c in s if c not in vowels)
For only 5 vowels, both approaches have similar performance. The string approach is actually slightly faster due to less overhead. However, if checking against a larger character set, a set would provide better O(1) average-case lookup time.
4. Not Preserving Non-Alphabetic Characters
The current solution correctly preserves all non-vowel characters including digits, spaces, and special characters. A pitfall would be accidentally filtering these out:
Incorrect approach:
def removeVowels(self, s: str) -> str:
# Wrong: This would only keep consonants, removing numbers and symbols
consonants = "bcdfghjklmnpqrstvwxyz"
return "".join(c for c in s if c in consonants)
The correct approach keeps everything except vowels, which the original solution handles properly.
Consider the classic dynamic programming of longest increasing subsequence:
Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.
For example, the length of LIS for [50, 3, 10, 7, 40, 80]
is 4
and LIS is
[3, 7, 40, 80]
.
What is the recurrence relation?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!