Python 2063.py
class Solution:
def countVowels(self, word: str) -> int:
result = 0
for i, c in enumerate(word):
if c in "aeiou":
left = i + 1 # prefix
right = len(word) - i # suffix
result += left * right # all combinations of prefix and suffix
return result
Difficulty
and has an acceptance rate of about 56% (80k+ submissions).
Typical patterns to solve this problem:
- Combinatorics
- Dynamic Programming
- Math
- 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 Solution class with a single method countVowels. The method receives a string word and returns an integer representing the total number of vowel appearances across all possible substrings of the input. The algorithm iterates once over the characters of the string, identifies vowel positions, and for each vowel computes the number of substrings that contain it by multiplying the count of possible prefix lengths with the count of possible suffix lengths. The accumulated sum is then returned.
Core Logic
The method begins by initializing an accumulator named result to zero. This variable holds the running total of vowel contributions.
result = 0
A for loop enumerates the characters of word, exposing both the index i and the character c. Enumeration is crucial because the position of each character determines how many substrings can include it.
for i, c in enumerate(word):
Inside the loop, a membership test checks whether the current character belongs to the set of lowercase English vowels "aeiou". The test is performed using the in operator, which runs in constant time for a short literal string.
if c in "aeiou":
When a vowel is found, two quantities are derived:
left- the number of possible starting positions for a substring that ends at or after the vowel. Because a substring can start at any index from0up toi, the count equalsi + 1.right- the number of possible ending positions for a substring that starts at or before the vowel. Since the substring can end at any index fromitolen(word) - 1, the count equalslen(word) - i.
left = i + 1 # prefix
right = len(word) - i # suffix
The product left * right yields the total number of distinct substrings that contain the vowel at position i. This product is added to result.
result += left * right # all combinations of prefix and suffix
After the loop finishes, the method returns the accumulated value.
return result
The entire flow can be visualized as a single pass that transforms each vowel into a contribution based on its combinatorial reach within the string.
Edge Cases Handled
The algorithm gracefully handles several boundary conditions without additional code:
- Empty string - The loop body never executes, leaving
resultat its initial value of0. The method correctly returns0, reflecting that no substrings exist. - String without vowels - The
ifcondition never succeeds, soresultremains0. This correctly indicates that no vowel appears in any substring. - String consisting solely of vowels - Every character triggers the contribution calculation. For a string of length
n, the total equals the sum ofi+1timesn-ifor each indexi, which matches the combinatorial expectation. - Single-character strings - When the character is a vowel,
leftandrightboth evaluate to1, and the method returns1. If the character is a consonant, the method returns0. Both outcomes are correct. - Mixed case input - The membership test checks only lowercase vowels. Consequently, uppercase vowels are ignored, which aligns with the function’s implicit contract of handling lowercase input only.
Performance Characteristics
The implementation exhibits several performance-friendly traits:
- Linear traversal - By iterating once over the input string, the algorithm runs in time proportional to the length of
word. No nested loops or recursive calls are introduced. - Constant-time operations inside the loop - The vowel check, arithmetic calculations, and accumulator update each execute in O(1) time. The use of a literal string for the vowel set avoids the overhead of constructing a data structure on each iteration.
- Minimal memory footprint - Apart from the input string and a few integer variables (
result,i,left,right), the method does not allocate additional containers. This keeps auxiliary memory usage low. - Avoidance of substring generation - Rather than materializing each possible substring, the algorithm computes the contribution analytically. This eliminates the combinatorial explosion that would arise from explicit substring creation, preserving both speed and memory.
Overall, the code delivers an efficient solution for counting vowel occurrences across all substrings by leveraging combinatorial insight and a straightforward single-pass design.
ELI5 - Simplified Explanation
Imagine you have a long, colorful train made of alphabet blocks. This code is like a little helper that wants to count how many special windows appear in every possible piece of that train. The special windows are the vowels, which are the letters a, e, i, o, and u.
The code looks at each letter in the train one by one. When it finds a vowel, it stops to see how many different parts of the train include that specific block. It counts how many ways it can pick a piece that starts before the vowel and ends after the vowel. To do this, it counts how many blocks are to the left of the vowel and how many blocks are to the right. By multiplying those two numbers, the helper finds every possible trip that goes through that vowel. It adds all those little trips together until it has checked every single block in the train.
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++ | Java | Python | TS | |||||
| WalkCCC | C++ | Java | Python | |||||||
| leetcode.ca | C++ | JS | Java | Python | Go | Rust | TS | |||
| Progiez | C++ | Java | Python | |||||||
| github | black-shadows | C++ | ||||||||
| charles-wangkai | Java | |||||||||
| everthis | JS | |||||||||
| fartem | Ruby | |||||||||
| fsq | C++ | |||||||||
| JoshCrozier | JS | |||||||||
| lkwq007 | Python | |||||||||
| suxrobGM | C# | |||||||||
| varunu28 | Java | |||||||||
| AlgoMonster | C++, Python, Java, TypeScript | |||||||||
| WalkCCC | C++, Python, Java | |||||||||
| leetcode.ca | C++, Go, Java, JavaScript, Python, Rust, TypeScript | |||||||||
| Progiez | C++, Java, Python | |||||||||
| black-shadows | C++, C++ | |||||||||
| charles-wangkai | Java | |||||||||
| everthis | JavaScript | |||||||||
| fartem | Ruby | |||||||||
| fsq | C++ | |||||||||
| JoshCrozier | JavaScript | |||||||||
| lkwq007 | Python | |||||||||
| suxrobGM | C# | |||||||||
| varunu28 | Java |
Videos
Similar Problems
- problem 1358: Number of Substrings Containing All Three Characters
- problem 2262: Total Appeal of A String
Solved On The Same Day
- problem 1288: Remove Covered Intervals
- problem 1509: Minimum Difference Between Largest and Smallest Value in Three Moves
- problem 2279: Maximum Bags With Full Capacity of Rocks
- problem 2924: Find Champion II
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