Facebook Pixel

1119. Remove Vowels from a String 🔒

EasyString
Leetcode Link

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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. Character Traversal: We iterate through each character c in the input string s using a generator expression for c in s.

  2. Vowel Check: For each character, we check if it's a vowel using the condition c not in "aeiou". This leverages Python's in 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.

  3. 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, and join() 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 Evaluator

Example 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.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More