Problem 1839

Abstract / Summary

Find the longest string in the given string that contains all vowels in order.

Note

The full problem description, including helpful examples, can be found on LeetCode.

Python 1839.py

class Solution:
    def longestBeautifulSubstring(self, word: str) -> int:
        result = 0

        # next vowel
        next   = { "a": "e", "e": "i", "i": "o", "o": "u" }

        prev   = ""    # last vowel
        length = 0     # length of currently processed substring
        valid  = False # true if current character belongs to a sequence starting with "a"
        for c in word:
            # must start with "a"
            if not valid:
                if c == "a":
                    valid  = True
                    length = 1
            # same vowel or next vowel in alphabetical order
            elif c == prev or c == next.get(prev, ""):
                length += 1
            # abort
            else:
                if c == "a":
                    length = 1     # immediately restart new sequence
                else:
                    valid  = False # keep idling, wait for "a"

            prev = c

            # sequence complete (but there may be more "u")
            if valid and c == "u":
                result = max(result, length)

        return result
33 lines | 1131 bytes | submitted January 24, 2024 | GitHub   43% comment ratio | tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 52% (80k+ submissions).

Typical patterns to solve this problem:
  • Sliding Window
  • String
I solved 663 easy, 1250 medium and 309 hard problems

AI Disclaimer

Every single line of code was written by me, 100% from scratch, between August 2023 and August 2024.
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.

See this dedicated page for more details.
LeetCode profile | GitHub repo

Code Walkthrough

Overview

The provided implementation defines a method that scans a given string to find the length of the longest contiguous substring that contains all five English vowels in order - “a”, “e”, “i”, “o”, “u”. The substring may contain repeated occurrences of each vowel, but the sequence must never regress to an earlier vowel. The algorithm returns zero when no such ordered vowel sequence exists.

Key Steps

The method begins by establishing a result accumulator, a mapping that identifies the next vowel in the required order, and several state variables that track the current processing context.

result = 0
next   = { "a": "e", "e": "i", "i": "o", "o": "u" }
prev   = ""    # last vowel seen
length = 0     # length of the substring under consideration
valid  = False # indicates whether we are inside a candidate sequence

The core of the solution is a single pass over the characters of the input string. For each character the algorithm decides whether to start a new candidate, extend the current one, or abort it.

for c in word:
    # must start with "a"
    if not valid:
        if c == "a":
            valid  = True
            length = 1

When a candidate sequence is already active, the next character is accepted if it matches the previous vowel (allowing repeats) or if it is the immediate successor according to the predefined order.

    elif c == prev or c == next.get(prev, ""):
        length += 1

If the character does not satisfy either condition, the current candidate is terminated. The algorithm then checks whether the offending character itself can serve as the start of a new sequence; if it is an “a”, the length counter is reset to one, otherwise the state is cleared and the loop continues waiting for the next “a”.

    else:
        if c == "a":
            length = 1     # immediately restart new sequence
        else:
            valid  = False # keep idling, wait for "a"

At the end of each iteration the previous character reference is updated, and whenever a “u” is encountered while a candidate is active, the current length is compared against the best result found so far.

    prev = c
    if valid and c == "u":
        result = max(result, length)

Finally, the method returns the maximum length recorded.

return result

Edge Cases Handled

The algorithm gracefully handles an empty input string because the loop body never executes, leaving the result at its initial zero value. A string that contains no “a” also yields zero, as the valid flag never becomes true. When the input consists solely of a single vowel, the logic permits a start only on “a”, so substrings like “e” or “i” are ignored, while a solitary “a” does not produce a valid result because the required “u” is never reached.

Repeated occurrences of the same vowel are accepted by the c == prev condition, allowing substrings such as “aaeeii” to be processed without premature termination. The mapping next ensures that only the correct forward transition is allowed; for example, a jump from “a” directly to “i” is rejected, causing the current candidate to abort.

Extra trailing “u” characters are accommodated because the result update occurs on every “u” while the candidate remains valid. Consequently, a substring like “aeiouu” correctly reports a length of seven, reflecting the additional “u”.

When a non-vowel character appears inside a candidate, the else branch resets the state. If that character happens to be an “a”, the algorithm instantly begins a new candidate with length one, thereby handling patterns such as “aeia” without missing a potential later sequence.

Performance Optimizations

The solution operates with a single linear traversal of the input, guaranteeing that each character is examined exactly once. All auxiliary data structures are of constant size: the next dictionary contains four entries, and the state variables occupy a fixed amount of memory, resulting in a minimal memory footprint independent of input length.

By updating the result only when a “u” is observed, the algorithm avoids unnecessary comparisons for intermediate characters, reducing the number of conditional evaluations. The early-exit style in the else block-resetting the candidate immediately when an “a” is encountered-prevents the need for a secondary scan to locate the next possible start point.

Overall, the design leverages straightforward control flow and constant-time dictionary lookups to achieve efficient execution while maintaining clear logical separation of the start, continuation, and abort phases.

written by openai gpt

ELI5 - Simplified Explanation

Imagine you are building a long, colorful train out of toy blocks. Each block has a letter on it, and the goal is to line them up in a very specific order. The train track only accepts blocks if they follow the pattern of the vowels a, e, i, o, and u.

The helper tool keeps a list of which letter should come after another. It looks at the alphabet blocks one by one to see if they fit the pattern. If a block is an a, the train ride starts. If the next block matches the letter that belongs right after the one before it, the train gets longer.

If a block does not follow the rule, the train has to stop and let go of those blocks. If the bad block happens to be an a, it might start a brand new train right away. The tool watches the whole line of blocks from start to finish. When the train finishes with a u, the tool checks if that train is the longest one seen so far. It keeps track of the longest train by comparing it to any other trains made earlier.

written by google gemini

Code Quality

Several LLMs ranked my code quality on a scale from 1 (very poor) to 10 (outstanding):
n = 27 | median = 7 | μ = 7.15 | σ = 1.35

Complexity Analysis

Time: linear
As a rule of thumb, the maximum input size for one second execution time is
  • factorial: up to 10 elements
  • exponential: up to 20 elements
  • polynomial: a few thousand elements
  • loglinear: up to 100,000 elements
  • linear: a few million elements
  • logarithmic: a billion elements
  • constant: practically unlimited
generated automatically

Other Solutions

I wrote a basic crawler to find other solutions to that problem.
Obviously, I did that after I solved the problem myself.

In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.

And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.

(click on a column header to sort the table)
author
author solutions
www AlgoMonster C++ Python Java TS
WalkCCC C++ Python Java
leetcode.ca C++ Python Java Go
Progiez C++ Python Java
github black-shadows C++
charles-wangkai Java
everthis JS
fsq C++
haoel C++
JoshCrozier JS
lkwq007 Python
MacJim C++
suxrobGM C#
trung-hn Python
wisdompeak C++
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, Go, Java, Python
Progiez C++, Java, Python
black-shadows C++, C++
charles-wangkai Java
everthis JavaScript
fsq C++
haoel C++
JoshCrozier JavaScript
lkwq007 Python
MacJim C++
suxrobGM C#
trung-hn Python
wisdompeak C++
25 links | 15 authors | 7 languages

Videos

3 videos   did my crawler come up with invalid videos ? drop me a line.

Similar Problems

1 similar problem

Solved On The Same Day

5 solutions   January 24, 2024

Extra

There are a few extra pages giving you some insights into my setup:
  • Tech Stack - my development environment and tools
  • AI - how AI helped me create this website (NOT solving the problems)
  • Progress - progression over time
  • Quality - code quality