Example 1
ready- Input
word = "aeiouu"- Expected
2- Why
- both 'aeiou' and 'aeiouu' contain every vowel
A consonant acts like a wall: no vowel-only stretch can pass through it. Between those walls, though, one long run may hide many overlapping answers.
Given a lowercase string word, count its vowel substrings. A vowel substring is a
non-empty, contiguous slice that uses only a, e, i, o, and u, while containing
all five of them at least once.
A few ground rules:
1 <= word.length <= 100_000word contains only lowercase English letters.Hints
Split your reasoning into uninterrupted vowel-only runs. Every valid answer lives entirely inside one run, so a consonant can reset all your state.
Start at each position and extend right until you hit a consonant. Track which vowel types you've seen, and count every endpoint after all five are present.
Inside one vowel run, keep a window containing all five types. Remove duplicate vowels from its left edge. Once it is as tight as possible, every start from the run's beginning through that left edge forms a valid substring ending here.
Can you count every answer in one left-to-right pass while storing only five small counters?
Visible cases
word = "aeiouu"2word = "aeioubcaeiou"2word = "rhythm"0Interview signal
Try every starting position. Extend right until a consonant blocks the slice, recording the vowel types you meet. Once all five types have appeared, this endpoint and every later endpoint before the next consonant can contribute an answer.
def count_vowel_substrings(word: str) -> int:
vowels = set("aeiou")
total = 0
for start in range(len(word)):
seen: set[str] = set()
for end in range(start, len(word)):
char = word[end]
if char not in vowels:
break
seen.add(char)
if len(seen) == 5:
total += 1
return totalTime O(n²) in a long vowel-only string. Space O(1) because seen holds at most
five characters.
A maximal vowel run is an uninterrupted block of vowels bordered by consonants or the ends of the string. Process each run with one window.
Keep a count for each vowel, plus distinct, the number of vowel types currently in the
window. When all five are present, move left past duplicate copies while preserving
at least one of every type. The window is now tight: moving left again would lose a
required vowel.
For the current right, every start from run_start through left is valid. There are
left - run_start + 1 such starts. A consonant clears the five counters and starts a new
run.
def count_vowel_substrings(word: str) -> int:
vowel_index = {"a": 0, "e": 1, "i": 2, "o": 3, "u": 4}
counts = [0] * 5
distinct = 0
left = 0
run_start = 0
total = 0
for right, char in enumerate(word):
index = vowel_index.get(char)
if index is None:
counts = [0] * 5
distinct = 0
left = right + 1
run_start = right + 1
continue
if counts[index] == 0:
distinct += 1
counts[index] += 1
if distinct == 5:
left_index = vowel_index[word[left]]
while counts[left_index] > 1:
counts[left_index] -= 1
left += 1
left_index = vowel_index[word[left]]
total += left - run_start + 1
return totalWhy count all starts through left? The tight window proves the slice beginning at
left has all five vowels. Starting earlier stays inside the same vowel run and only
adds vowels, so those starts work too. Starting later drops the leftmost required vowel.
Time O(n) — right and left each move forward only. Space O(1) for five fixed
counters and the vowel lookup.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
2