LeetCode 3813 - Vowel-Consonant Score
The problem asks us to compute a score for a given string s. The string may contain lowercase English letters, spaces, and digits. We need to count two quantities: - v, the number of vowels in the string. - c, the number of consonants in the string.
Difficulty: 🟢 Easy
Topics: String, Simulation
Solution
LeetCode 3813 - Vowel-Consonant Score
Problem Understanding
The problem asks us to compute a score for a given string s. The string may contain lowercase English letters, spaces, and digits.
We need to count two quantities:
v, the number of vowels in the string.c, the number of consonants in the string.
The vowels are exactly the letters 'a', 'e', 'i', 'o', and 'u'.
Any other English letter from 'a' to 'z' that is not a vowel is considered a consonant. Spaces and digits are neither vowels nor consonants, so they should not contribute to either count.
Once the counts are known, the score is defined as:
floor(v / c)if there is at least one consonant (c > 0).0if there are no consonants (c = 0).
The task is to return this score as an integer.
The constraints are very small:
1 <= s.length <= 100- The string contains only lowercase letters, spaces, and digits.
Since the input size is at most 100 characters, any algorithm that scans the string once or even multiple times would be fast enough. The challenge is simply implementing the counting logic correctly.
Several edge cases are important:
- A string containing only vowels should return
0because there are no consonants. - A string containing only consonants should return
0becausev = 0. - Spaces and digits must be ignored completely.
- A string with mixed letters, spaces, and digits should count only alphabetic characters.
Approaches
Brute Force Approach
A straightforward approach is to iterate through the string and, for each character, determine whether it is a vowel or consonant.
One possible brute force implementation checks every letter against the vowel list one by one. For each alphabetic character, we compare it with 'a', 'e', 'i', 'o', and 'u'. If a match is found, we increment the vowel count. Otherwise, if the character is a letter, we increment the consonant count.
After counting, we compute the score according to the problem definition.
This approach is correct because every character is examined and classified appropriately. However, checking against the vowel list repeatedly introduces unnecessary work.
Optimal Approach
The key observation is that vowel membership can be checked in constant time using a set.
We create a set containing the five vowels. Then we scan the string once:
- If a character is a letter and belongs to the vowel set, increment
v. - If a character is a letter but not in the vowel set, increment
c. - Ignore digits and spaces.
After the scan:
- Return
0ifc == 0. - Otherwise return
v // c.
This solution performs a single pass through the string and uses constant extra space.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n) | O(1) | Scan string and compare each letter against all vowels individually |
| Optimal | O(n) | O(1) | Single pass with constant time vowel lookup using a set |
Algorithm Walkthrough
- Create a set containing the vowels
{a, e, i, o, u}for fast membership testing. - Initialize two counters:
vowels = 0consonants = 0
- Iterate through every character in the string.
- For each character, first check whether it is an English letter. Characters that are spaces or digits are ignored because they do not affect either count.
- If the character is a letter and appears in the vowel set, increment the vowel counter.
- Otherwise, the character is a consonant, so increment the consonant counter.
- After processing the entire string, check whether the consonant count is zero.
- If
consonants == 0, return0because the problem explicitly defines the score as zero in this case. - Otherwise, return
vowels // consonants, which performs integer division and automatically computes the floor value required by the problem.
Why it works
The algorithm examines every character exactly once and classifies each alphabetic character into one of two mutually exclusive categories: vowel or consonant. Non-alphabetic characters are ignored, exactly as required by the problem statement. Therefore, after the traversal, vowels equals the true number of vowels and consonants equals the true number of consonants. The final computation directly follows the score definition, guaranteeing a correct result.
Python Solution
class Solution:
def vowelConsonantScore(self, s: str) -> int:
vowels_set = {"a", "e", "i", "o", "u"}
vowels = 0
consonants = 0
for ch in s:
if ch.isalpha():
if ch in vowels_set:
vowels += 1
else:
consonants += 1
if consonants == 0:
return 0
return vowels // consonants
The implementation begins by creating a set of vowels. Using a set allows constant time membership checks.
Two counters are maintained throughout the traversal. As each character is processed, isalpha() filters out spaces and digits. Alphabetic characters are then classified as vowels or consonants.
After the scan is complete, the code checks whether any consonants were found. If not, the answer is 0. Otherwise, integer division // computes the required floor value of v / c.
Go Solution
func vowelConsonantScore(s string) int {
vowels := map[rune]bool{
'a': true,
'e': true,
'i': true,
'o': true,
'u': true,
}
vowelCount := 0
consonantCount := 0
for _, ch := range s {
if ch >= 'a' && ch <= 'z' {
if vowels[ch] {
vowelCount++
} else {
consonantCount++
}
}
}
if consonantCount == 0 {
return 0
}
return vowelCount / consonantCount
}
The Go solution follows the same logic as the Python version. A map provides constant time vowel lookup. Since the problem guarantees lowercase English letters, spaces, and digits, checking whether a character lies between 'a' and 'z' is sufficient to identify alphabetic characters. Integer division in Go automatically performs floor division for positive integers, matching the problem requirements.
Worked Examples
Example 1
Input: s = "cooear"
| Character | Action | Vowels | Consonants |
|---|---|---|---|
| c | consonant | 0 | 1 |
| o | vowel | 1 | 1 |
| o | vowel | 2 | 1 |
| e | vowel | 3 | 1 |
| a | vowel | 4 | 1 |
| r | consonant | 4 | 2 |
Final values:
v = 4c = 2
Score:
4 // 2 = 2
Output:
2
Example 2
Input: s = "axeyizou"
| Character | Action | Vowels | Consonants |
|---|---|---|---|
| a | vowel | 1 | 0 |
| x | consonant | 1 | 1 |
| e | vowel | 2 | 1 |
| y | consonant | 2 | 2 |
| i | vowel | 3 | 2 |
| z | consonant | 3 | 3 |
| o | vowel | 4 | 3 |
| u | vowel | 5 | 3 |
Final values:
v = 5c = 3
Score:
5 // 3 = 1
Output:
1
Example 3
Input: s = "au 123"
| Character | Action | Vowels | Consonants |
|---|---|---|---|
| a | vowel | 1 | 0 |
| u | vowel | 2 | 0 |
| space | ignored | 2 | 0 |
| 1 | ignored | 2 | 0 |
| 2 | ignored | 2 | 0 |
| 3 | ignored | 2 | 0 |
Final values:
v = 2c = 0
Since there are no consonants, the score is defined as:
0
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each character is processed exactly once |
| Space | O(1) | Only a few counters and a fixed-size vowel set are stored |
The algorithm performs a single linear scan through the string. Since each character requires only constant work, the running time is proportional to the string length. The vowel set always contains exactly five elements, so the extra memory usage remains constant regardless of input size.
Test Cases
sol = Solution()
assert sol.vowelConsonantScore("cooear") == 2 # example 1
assert sol.vowelConsonantScore("axeyizou") == 1 # example 2
assert sol.vowelConsonantScore("au 123") == 0 # example 3
assert sol.vowelConsonantScore("a") == 0 # single vowel
assert sol.vowelConsonantScore("b") == 0 # single consonant
assert sol.vowelConsonantScore("aeiou") == 0 # all vowels
assert sol.vowelConsonantScore("bcdfg") == 0 # all consonants
assert sol.vowelConsonantScore("a1b2c3") == 0 # vowels=1, consonants=2
assert sol.vowelConsonantScore("aeioub") == 5 # vowels=5, consonants=1
assert sol.vowelConsonantScore("abcde") == 0 # vowels=2, consonants=3
assert sol.vowelConsonantScore(" ") == 0 # only spaces
assert sol.vowelConsonantScore("12345") == 0 # only digits
assert sol.vowelConsonantScore("a e i o u") == 0 # vowels separated by spaces
assert sol.vowelConsonantScore("abcdefghijklmnopqrstuvwxyz") == 0 # 5//21
| Test | Why |
|---|---|
"cooear" |
Validates the first example |
"axeyizou" |
Validates the second example |
"au 123" |
Validates handling of digits and spaces |
"a" |
Single vowel case |
"b" |
Single consonant case |
"aeiou" |
No consonants present |
"bcdfg" |
No vowels present |
"a1b2c3" |
Mixed letters and digits |
"aeioub" |
Large vowel count with one consonant |
"abcde" |
Integer floor division behavior |
" " |
Only spaces |
"12345" |
Only digits |
"a e i o u" |
Vowels separated by spaces |
"abcdefghijklmnopqrstuvwxyz" |
Full alphabet coverage |
Edge Cases
No Consonants Exist
A string such as "aeiou" or "au 123" contains vowels but no consonants. A careless implementation might attempt to divide by zero. The problem explicitly states that the score should be 0 when c = 0. The implementation handles this by checking if consonants == 0 before performing division.
No Vowels Exist
A string such as "bcdfg" contains only consonants. In this case, v = 0 and c > 0, so the score should be 0 // c = 0. The algorithm naturally produces this result through integer division.
Presence of Spaces and Digits
Strings may contain spaces and digits, such as "a1b2c3" or "au 123". These characters are neither vowels nor consonants and must not affect the counts. The implementation explicitly filters for alphabetic characters before classifying them, ensuring that spaces and digits are ignored.
Minimum Length Input
The smallest possible input length is one character. Examples include "a" and "b". The algorithm still works correctly because it initializes the counters properly and processes every character using the same logic regardless of string length.
Large Ratio of Vowels to Consonants
A string such as "aeioub" has five vowels and one consonant. The correct score is 5. The implementation uses integer division only after the counts are fully computed, producing the exact floor value required by the problem.