Longest Vowel Substring in JS
The challenge
Given a lowercase string of letters (no spaces, no digits), return the length of the longest substring made only of vowels (aeiou).
Examples:
solve("codewarriors"); // → 2 (the "io" in warriors)
solve("suoidea"); // → 3 (the "uoi")
solve("aeioaexaeuoiou"); // → 7 (the "aeuoiou")
solve("bcd"); // → 0
solve("a"); // → 1
The Codewars Kata in the JavaScript track uses aeioaexaeuoiou as a tie-breaker test. The two vowel runs in that string are aeioae (6) and aeuoiou (7) — the answer is 7.
Solution 1: single-pass counter (fastest)
Track the current vowel run length and update the maximum:
function solve(s) {
const vowels = new Set("aeiou");
let longest = 0;
let current = 0;
for (const ch of s) {
if (vowels.has(ch)) {
current++;
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 to zero. Keep the maximum seen so far. O(n) time, O(1) extra space.
Using new Set("aeiou") makes the membership test O(1). For five characters the difference is negligible, but it scales for larger alphabets.
Solution 2: regex one-liner
function solve(s) {
const matches = s.match(/[aeiou]+/g);
return matches ? Math.max(...matches.map(m => m.length)) : 0;
}
How it works: [aeiou]+ matches every run of one or more consecutive vowels. match with the /g flag returns them all as an array (or null if none). Math.max(...arr) picks the longest. The ternary handles the all-consonants case where match returns null.
Solution 3: split on consonants
function solve(s) {
const parts = s.split(/[^aeiou]+/).filter(Boolean);
return parts.length ? Math.max(...parts.map(p => p.length)) : 0;
}
How it works: Split on any run of non-vowel characters; the result is an array of vowel-only chunks. .filter(Boolean) drops empty strings (which happen when the input starts or ends with consonants). Math.max picks the largest length.
Walkthrough: aeioaexaeuoiou
Trace the single-pass counter 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 |
| 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 |
The first run (aeioae) is length 6. The second run (aeuoiou) is length 7 — that is the winner.
Complexity
| Solution | Time | Space |
|---|---|---|
| Single-pass counter | O(n) | O(1) |
Regex [aeiou]+ |
O(n) | O(n) |
| split on consonants | O(n) | O(n) |
For very long inputs the single-pass loop wins on both speed and memory because it does not allocate any arrays.
Test cases
console.assert(solve("codewarriors") === 2);
console.assert(solve("suoidea") === 3);
console.assert(solve("bcd") === 0);
console.assert(solve("a") === 1);
console.assert(solve("aeiou") === 5);
console.assert(solve("aeioaexaeuoiou") === 7);
console.assert(solve("") === 0);
Related challenges
- Longest vowel substring in Java — the Java version of this exact puzzle.
- Longest vowel substring in Python — the Python translation.
- Longest alphabetical substring in JavaScript — same “longest run” pattern, applied to character ordering instead of vowel membership.