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
Difficulty
and has an acceptance rate of about 52% (80k+ submissions).
Typical patterns to solve this problem:
- Sliding Window
- String
AI Disclaimer
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.
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.
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.
Code Quality
Complexity Analysis
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
Other Solutions
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++ |
Videos
Similar Problems
- problem 2062: Count Vowel Substrings of a String
Solved On The Same Day
- problem 1854: Maximum Population Year
- problem 1869: Longer Contiguous Segments of Ones than Zeros
- problem 1239: Maximum Length of a Concatenated String with Unique Characters
- problem 1855: Maximum Distance Between a Pair of Values
Extra
- 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