Longest Vowel Substring in Python
The challenge
Given a lowercase string of letters (no spaces, no digits), return the length of the longest substring that contains only vowels (aeiou).
Examples:
solve("codewarriors") # → 2 (the "io" in warriors)
solve("suoidea") # → 3 (the "uoi")
solve("aeioaexaeuoiou") # → 5 (the "aeioa" or "uoiou")
solve("bcd") # → 0
solve("a") # → 1
The puzzle appears in Codewars in both Python and Java tracks. The aeioaexaeuoiou test case is the classic gotcha — make sure you handle two equally-long winners.
Solution 1: single-pass counter (fastest)
Track the current vowel run length and update the maximum:
def solve(s):
vowels = set("aeiou")
longest = current = 0
for ch in s:
if ch in vowels:
current += 1
if current > longest:
longest = current
else:
current = 0
return longest
How it works: Walk the string once. If the character is a vowel, extend the current run; otherwise reset it. Keep the maximum seen. O(n) time, O(1) space.
Using set("aeiou") instead of the string "aeiou" makes membership testing O(1) instead of O(5) — small win, but it scales.
Solution 2: regex one-liner
import re
def solve(s):
matches = re.findall(r"[aeiou]+", s)
return max((len(m) for m in matches), default=0)
How it works: [aeiou]+ matches one or more consecutive vowels. findall returns every such run as a list, and max picks the longest. The default=0 argument prevents ValueError on strings with no vowels.
Solution 3: split + max
A pure-Python alternative without regex:
def solve(s):
consonants = "bcdfghjklmnpqrstvwxyz"
table = str.maketrans({c: " " for c in consonants})
return max(map(len, s.translate(table).split()), default=0)
How it works: Replace every consonant with a space, then split() on whitespace gives the vowel-only chunks. map(len, ...) measures each chunk; max picks the largest. default=0 handles the all-consonants case.
Walkthrough: aeioaexaeuoiou
The famous Codewars test case. Trace it character by character:
| Char | Vowel? | current | longest |
|---|---|---|---|
| a | yes | 1 | 1 |
| e | yes | 2 | 2 |
| i | yes | 3 | 3 |
| o | yes | 4 | 4 |
| a | yes | 5 | 5 |
| e | yes | 6 | 6 ← actually 6, not 5 |
| x | no | 0 | 6 |
| a | yes | 1 | 6 |
| e | yes | 2 | 6 |
| u | yes | 3 | 6 |
| o | yes | 4 | 6 |
| i | yes | 5 | 6 |
| o | yes | 6 | 6 |
| u | yes | 7 | 7 |
Wait — the answer is 7, not 5. The two vowel runs are aeioae (length 6) and aeuoiou (length 7). Always trace by hand before trusting your intuition on tie-breaker test cases.
Complexity
| Solution | Time | Space |
|---|---|---|
| Single-pass counter | O(n) | O(1) |
Regex [aeiou]+ |
O(n) | O(n) |
| translate + split | O(n) | O(n) |
The single-pass version is preferred for very long inputs (10,000+ chars) because it does not allocate a list of all matches.
Test cases
assert solve("codewarriors") == 2
assert solve("suoidea") == 3
assert solve("bcd") == 0
assert solve("a") == 1
assert solve("aeiou") == 5
assert solve("aeioaexaeuoiou") == 7
assert solve("") == 0
Related challenges
- Longest vowel substring in Java — the Java version of this exact puzzle.
- Longest alphabetical substring in Python — same “longest run” pattern, but checking alphabetical order rather than vowels.
- Remove all vowels from a string in Python — the inverse problem.