Facebook Pixel

3856. Trim Trailing Vowels

EasyString
LeetCode ↗

Problem Description

You are given a string s made up of lowercase English letters.

Your task is to remove all trailing vowels from s and return the resulting string.

The vowels are the characters 'a', 'e', 'i', 'o', and 'u'.

In other words, starting from the end of the string, you keep deleting characters as long as they are vowels. Once you reach a character that is not a vowel (a consonant), you stop, and return the portion of the string from the beginning up to and including that character.

For example, if s = "leetcode", the last character 'e' is a vowel, so it gets removed. The next character from the end is 'd', which is a consonant, so the trimming stops. The result is "leetcod".

If every character in the string is a vowel, the result is an empty string.

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

How We Pick the Algorithm

Why Simulation / Basic DSA?

This problem maps to Simulation / Basic DSA through a short path in the full flowchart.

Straightforwardstep-by-step?yesMath orbitmanipulation?noSimulation /Basic DSA

Scan backwards from the end removing vowels until a consonant is found, a simple linear traversal with no algorithmic pattern needed.

Open in Flowchart

Intuition

The key observation is that we only care about the trailing vowels — the vowels that appear at the very end of the string. The characters in the middle or at the beginning do not matter, even if they are vowels.

Since we want to remove characters from the end, it makes sense to look at the string starting from its last character and move backwards. As long as the character we are looking at is a vowel, it belongs to the trailing run of vowels and should be removed. The moment we hit a character that is not a vowel, we know the trailing vowels have ended, so we stop.

At that point, the position of the first non-vowel character (scanning from the right) tells us exactly where the answer should end. Everything from the start of the string up to and including that character is the part we want to keep, and everything after it was a trailing vowel.

This naturally leads us to use a pointer i starting at the last index and decreasing it while s[i] is a vowel. When the loop stops, s[: i + 1] gives the string with all trailing vowels removed. If the entire string consists of vowels, the pointer moves past the beginning and i + 1 becomes 0, correctly returning an empty string.

Solution Approach

Solution 1: Reverse Traversal

We traverse the string from the end in reverse order until we encounter the first non-vowel character. Then we return the substring from the beginning of the string up to that position.

The implementation follows these steps:

  1. Initialize a pointer. We set i = len(s) - 1, so that i points to the last character of the string. This pointer will move leftward as we skip over trailing vowels.

  2. Scan backwards while skipping vowels. We run a loop with two conditions:

    • i >= 0 ensures we stay within the bounds of the string and do not go past the beginning.
    • s[i] in "aeiou" checks whether the current character is a vowel.

    As long as both conditions hold, we decrement i by 1, effectively moving past each trailing vowel. The loop stops as soon as we either reach a non-vowel character or move past the start of the string.

  3. Return the trimmed string. After the loop ends, i points to the last non-vowel character (or to -1 if the whole string is made of vowels). We return s[: i + 1], which is the substring from the beginning up to and including index i. The slice s[: i + 1] naturally handles the empty-string case: when i = -1, it produces s[:0], which is "".

This approach uses a simple two-pointer / single-pointer scan pattern, where one pointer walks from the right toward the left. No extra data structures are needed, and we only look at each trailing vowel once.

The time complexity is O(n), where n is the length of the string, since in the worst case (an all-vowel string) we examine every character. The space complexity is O(1) for the pointer, not counting the space used by the returned substring.

Example Walkthrough

Let's trace through the algorithm using the example s = "consume".

The string has 7 characters, indexed as follows:

Index0123456
Charconsume

Step 1: Initialize the pointer.

We set i = len(s) - 1 = 6, so i starts at the last character 'e'.

Step 2: Scan backwards while skipping vowels.

  • i = 6: s[6] = 'e'. Since 'e' is a vowel, we decrement i to 5.
  • i = 5: s[5] = 'm'. Since 'm' is not a vowel (it's a consonant), the loop stops here.

The pointer settles at i = 5, which points to the last non-vowel character 'm'.

Step 3: Return the trimmed string.

We return s[: i + 1] = s[: 6] = "consum".

Notice that only the single trailing 'e' was removed. The vowels 'o' (index 1) and 'u' (index 4) sit in the middle of the string, so they are left untouched — exactly as intended, since we only care about the trailing run of vowels.

Edge case check — all vowels:

If instead s = "aeiou", the pointer would decrement past every character: 4 → 3 → 2 → 1 → 0 → -1. When the loop exits with i = -1, the slice s[: -1 + 1] = s[: 0] produces "", correctly returning the empty string.

Solution Implementation

1class Solution:
2    def trimTrailingVowels(self, s: str) -> str:
3        # Define the set of vowels for quick membership lookup
4        vowels = set("aeiou")
5
6        # Start scanning from the last character of the string
7        index = len(s) - 1
8
9        # Move the pointer leftward while the current character is a vowel
10        while index >= 0 and s[index] in vowels:
11            index -= 1
12
13        # Return the substring up to (and including) the last non-vowel character
14        return s[: index + 1]
15
1class Solution {
2    /**
3     * Removes all trailing vowels (a, e, i, o, u) from the end of the given string.
4     *
5     * @param s the input string to be processed
6     * @return the string with trailing vowels removed
7     */
8    public String trimTrailingVowels(String s) {
9        // Define the set of vowel characters to check against.
10        final String vowels = "aeiou";
11
12        // Start scanning from the last character of the string.
13        int index = s.length() - 1;
14
15        // Move the index leftward as long as the current character is a vowel.
16        while (index >= 0 && vowels.indexOf(s.charAt(index)) != -1) {
17            index--;
18        }
19
20        // Return the substring from the start up to and including the last non-vowel character.
21        return s.substring(0, index + 1);
22    }
23}
24
1class Solution {
2public:
3    string trimTrailingVowels(string s) {
4        // Set of vowel characters used for lookup.
5        const string vowels = "aeiou";
6
7        // Start scanning from the last character of the string.
8        int index = static_cast<int>(s.size()) - 1;
9
10        // Move the index backward while the current character is a vowel.
11        // string::npos indicates the character was NOT found in 'vowels',
12        // so the loop continues only when a vowel is found.
13        while (index >= 0 && vowels.find(s[index]) != string::npos) {
14            --index;
15        }
16
17        // Return the substring from the beginning up to (and including)
18        // the last non-vowel character. If all characters were vowels,
19        // index becomes -1 and an empty string is returned.
20        return s.substr(0, index + 1);
21    }
22};
23
1/**
2 * Removes all trailing vowels (a, e, i, o, u) from the given string.
3 *
4 * @param s - The input string to be trimmed.
5 * @returns A new string with any trailing vowels removed.
6 */
7function trimTrailingVowels(s: string): string {
8    // Define the set of vowels to check against.
9    const vowels = 'aeiou';
10
11    // Start from the last character of the string.
12    let index = s.length - 1;
13
14    // Move the index backwards while the current character is a vowel.
15    while (index >= 0 && vowels.indexOf(s[index]) !== -1) {
16        index--;
17    }
18
19    // Return the substring from the start up to (and including) the last
20    // non-vowel character. If all characters are vowels, this yields an empty string.
21    return s.slice(0, index + 1);
22}
23

Time and Space Complexity

  • Time complexity: O(n), where n is the length of the string s. In the worst case (e.g., when all characters are vowels), the while loop traverses the entire string from the end to the beginning, performing one comparison per character. The slicing operation s[: i + 1] also takes O(n) time in the worst case. Therefore, the overall time complexity is O(n).

  • Space complexity: O(1). Only a constant amount of extra space is used for the index variable i. Although the slicing operation creates a new string, this is typically considered as the output rather than auxiliary space, so the additional space usage is O(1).

Pattern Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Only removing a single trailing vowel instead of all of them

A very common mistake is to check just the last character once, remove it if it's a vowel, and then return immediately. This handles the simplest case but fails whenever there are multiple consecutive trailing vowels.

# WRONG: only strips one vowel
class Solution:
    def trimTrailingVowels(self, s: str) -> str:
        if s and s[-1] in "aeiou":
            return s[:-1]
        return s

For an input like s = "queue", the correct result is "q" (the trailing "ueue" are all vowels), but this code returns "queu". The fix is to use a loop that keeps moving the pointer leftward until a consonant is found, exactly as the reference solution does:

index = len(s) - 1
while index >= 0 and s[index] in vowels:
    index -= 1
return s[: index + 1]

Pitfall 2: Off-by-one error in the returned slice

After the loop ends, index points to the last non-vowel character. A frequent error is returning s[:index] instead of s[:index + 1], which accidentally drops the final consonant.

# WRONG: chops off the last valid consonant
return s[:index]   # for "leetcode" this yields "leetco" instead of "leetcod"

Remember that Python slicing is end-exclusive, so to include the character at index you must slice up to index + 1.

Pitfall 3: Mishandling the all-vowel (and empty) string case

When every character is a vowel (e.g., s = "aeiou"), the loop decrements index all the way down to -1. Some implementations attempt to special-case this or forget to guard the boundary, leading to an IndexError or an incorrect result.

# WRONG: missing the index >= 0 guard causes negative-index wrap-around
while s[index] in vowels:   # when index reaches -1, s[-1] wraps to the end!
    index -= 1

Without the index >= 0 condition, once index becomes -1, s[-1] wraps around to the last character of the string, producing an infinite loop or incorrect behavior. The reference solution handles this gracefully:

  • The condition index >= 0 stops the loop at the boundary.
  • The slice s[: index + 1] becomes s[:0], which correctly returns "".

Always check the bounds before indexing, and trust that the end-exclusive slice naturally produces an empty string for the all-vowel case.

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

What's the relationship between a tree and a graph?


Recommended Readings

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

Load More