Facebook Pixel

3813. Vowel-Consonant Score

EasyStringSimulation
LeetCode ↗

Problem Description

You are given a string s made up of lowercase English letters, spaces, and digits.

Let v be the number of vowels in s and c be the number of consonants in s.

  • A vowel is one of the letters 'a', 'e', 'i', 'o', or 'u'.
  • Any other letter in the English alphabet is considered a consonant.

Note that spaces and digits are not counted as vowels or consonants.

The score of the string s is defined as follows:

  • If c > 0, then score = floor(v / c), where floor means rounding down to the nearest integer.
  • Otherwise (when c == 0), the score = 0.

Your task is to return an integer representing the score of the string s.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Simulation / Basic DSA?

This problem maps to Simulation / Basic DSA through a short path in the full flowchart.

JustsimulatetheyesComplexdatastructure?noSimulation /Basic DSA

Counting vowels and consonants in a string and computing the floor division score is a direct simulation of the problem statement.

Open in Flowchart

Intuition

The score depends entirely on two quantities: the number of vowels v and the number of consonants c. So the natural first step is to figure out these two counts.

To do this, we look at each character in the string one by one. We only care about letters of the alphabet, so we skip over spaces and digits. For every letter we encounter, we check whether it is one of 'a', 'e', 'i', 'o', 'u'. If it is, it counts as a vowel; if not, it is a consonant.

A handy trick is to first count all letters (both vowels and consonants together) and separately count just the vowels. Then the number of consonants is simply total letters - vowels. This avoids writing a separate condition for consonants.

Once we have v and c, the score follows directly from the rule given:

  • If c == 0, there are no consonants to divide by, so the score is 0.
  • Otherwise, the score is v // c, where // performs integer division, which already rounds down to the nearest integer just like floor(v / c).

This gives us a clean single-pass approach over the string.

Solution Approach

Solution 1: Counting

We use a simple counting approach with a single pass over the string. No extra data structures are needed beyond two integer counters.

  1. Initialize two counters: v = 0 for vowels and c = 0 for letters.

  2. Iterate through every character ch in the string s:

    • Use ch.isalpha() to check whether ch is a letter. This automatically skips spaces and digits.
    • If ch is a letter, increment c (counting it as a letter for now).
    • Then check if ch is in the set "aeiou". If so, increment v as well.
  3. After the loop, c holds the count of all letters, while v holds the count of vowels. To get the actual number of consonants, subtract the vowels: c -= v.

  4. Finally, compute the score based on the problem rule:

    • If c == 0, return 0 since there are no consonants to divide by.
    • Otherwise, return v // c, where integer division // naturally rounds down to the nearest integer, matching floor(v / c).

The time complexity is O(n), where n is the length of the string, since we scan each character once. The space complexity is O(1), as we only use a constant number of variables.

Example Walkthrough

Let's trace through the solution using the string s = "hi3 boa".

We start with two counters: v = 0 (vowels) and c = 0 (letters). We then scan each character one by one.

Characterisalpha()?In "aeiou"?Actionvc
'h'YesNoc += 101
'i'YesYesc += 1, v += 112
'3'Noskip12
' 'Noskip12
'b'YesNoc += 113
'o'YesYesc += 1, v += 124
'a'YesYesc += 1, v += 135

After the loop, v = 3 and c = 5, but remember c currently counts all letters, not just consonants.

Step — convert c to consonant count: We subtract the vowels from the total letters: c -= vc = 5 - 3 = 2.

So we have v = 3 vowels (i, o, a) and c = 2 consonants (h, b). Notice the digit '3' and the space were correctly ignored.

Step — compute the score: Since c = 2 > 0, we apply integer division: score = v // c = 3 // 2 = 1.

The integer division // rounds down automatically, matching floor(3 / 2) = floor(1.5) = 1.

Result: the function returns 1.

As a quick edge-case check, consider s = "aei 9". Here every letter is a vowel, so after the scan v = 3 and c = 3, then c -= v gives c = 0. Because there are no consonants, we return 0 directly, avoiding division by zero.

Solution Implementation

1class Solution:
2    def vowelConsonantScore(self, s: str) -> int:
3        # Count of vowels found in the string
4        vowel_count = 0
5        # Count of consonants found in the string
6        consonant_count = 0
7
8        # Define the set of vowels for quick membership checking
9        vowels = set("aeiou")
10
11        # Iterate over each character in the input string
12        for ch in s:
13            # Only consider alphabetic characters (ignore digits, symbols, etc.)
14            if ch.isalpha():
15                if ch in vowels:
16                    # Character is a vowel
17                    vowel_count += 1
18                else:
19                    # Character is a consonant
20                    consonant_count += 1
21
22        # Avoid division by zero: if there are no consonants, return 0
23        if consonant_count == 0:
24            return 0
25
26        # Return the integer division of vowel count by consonant count
27        return vowel_count // consonant_count
28
1class Solution {
2    public int vowelConsonantScore(String s) {
3        // Count of vowels found in the string
4        int vowelCount = 0;
5        // Count of letters (later reduced to consonants only)
6        int letterCount = 0;
7
8        // Iterate over every character in the string
9        for (int i = 0; i < s.length(); i++) {
10            char ch = s.charAt(i);
11
12            // Only consider alphabetic characters
13            if (Character.isLetter(ch)) {
14                letterCount++;
15
16                // Check if the current character is a vowel
17                if ("aeiou".indexOf(ch) != -1) {
18                    vowelCount++;
19                }
20            }
21        }
22
23        // Subtract vowels from total letters to get the consonant count
24        int consonantCount = letterCount - vowelCount;
25
26        // Avoid division by zero; return the integer ratio of vowels to consonants
27        return consonantCount == 0 ? 0 : vowelCount / consonantCount;
28    }
29}
30
1class Solution {
2public:
3    int vowelConsonantScore(string s) {
4        int vowelCount = 0;      // Number of vowels in the string
5        int consonantCount = 0;  // Number of consonants in the string
6
7        // Iterate over each character in the string
8        for (char ch : s) {
9            // Only consider alphabetic characters
10            if (isalpha(static_cast<unsigned char>(ch))) {
11                // Convert to lowercase so the comparison is case-insensitive
12                char lower = static_cast<char>(tolower(static_cast<unsigned char>(ch)));
13
14                // Check whether the character is a vowel
15                if (string("aeiou").find(lower) != string::npos) {
16                    ++vowelCount;
17                } else {
18                    ++consonantCount;
19                }
20            }
21        }
22
23        // Avoid division by zero: if there are no consonants, the score is 0
24        return consonantCount == 0 ? 0 : vowelCount / consonantCount;
25    }
26};
27
1/**
2 * Calculates a score based on the ratio of vowels to consonants in a string.
3 * Only alphabetic characters are considered; all other characters are ignored.
4 *
5 * The score is computed as floor(vowelCount / consonantCount).
6 * If there are no consonants, the function returns 0 to avoid division by zero.
7 *
8 * @param s - The input string to evaluate.
9 * @returns The integer score derived from the vowel-to-consonant ratio.
10 */
11function vowelConsonantScore(s: string): number {
12    // Track the number of vowels and the total number of letters.
13    let vowelCount = 0;
14    let letterCount = 0;
15
16    // Iterate over each character in the string.
17    for (const char of s) {
18        // Only process alphabetic characters (a-z, A-Z).
19        if (/[a-zA-Z]/.test(char)) {
20            letterCount++;
21
22            // Check whether the current character is a lowercase vowel.
23            if ('aeiou'.includes(char)) {
24                vowelCount++;
25            }
26        }
27    }
28
29    // Derive the consonant count by subtracting vowels from the total letters.
30    const consonantCount = letterCount - vowelCount;
31
32    // Guard against division by zero, then return the floored ratio.
33    return consonantCount === 0 ? 0 : Math.floor(vowelCount / consonantCount);
34}
35

Time and Space Complexity

  • Time Complexity: O(n), where n is the length of the string s. The code iterates through each character of the string exactly once in the for loop. For each character, it performs constant-time operations (isalpha() check, membership check ch in "aeiou" against a fixed-size string, and increments). Therefore, the total time grows linearly with the length of the string.

  • Space Complexity: O(1). The algorithm uses only a constant amount of extra space, namely the variables v and c to track the counts of vowels and consonants, along with the loop variable ch. No additional data structures that scale with the input size are used.

Pattern Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Forgetting to Handle the c == 0 Case (Division by Zero)

The most common mistake is computing vowel_count // consonant_count directly without first checking whether consonant_count is zero. When the string contains no consonants (e.g., "aeiou", "a1 e2", or "12345"), this triggers a ZeroDivisionError in Python and crashes the program.

Why it happens: Developers focus on the main formula floor(v / c) and overlook the special rule that score = 0 when c == 0.

Example that breaks:

s = "aeiou"   # 5 vowels, 0 consonants
# vowel_count // consonant_count -> 5 // 0 -> ZeroDivisionError

Solution: Always guard the division with an explicit check, as the provided code does:

if consonant_count == 0:
    return 0
return vowel_count // consonant_count

Pitfall 2: Treating Digits or Spaces as Consonants

A subtle bug arises if you classify characters as consonants using a "not a vowel" rule without first confirming the character is a letter. For instance:

for ch in s:
    if ch in vowels:
        vowel_count += 1
    else:
        consonant_count += 1   # WRONG: counts spaces and digits too!

This incorrectly counts spaces and digits as consonants, inflating consonant_count and producing a wrong score.

Solution: Always verify the character is alphabetic first using ch.isalpha() before deciding vowel vs. consonant. This guarantees spaces and digits are skipped entirely.


Pitfall 3: Using Float Division Instead of Integer Division

Some implementations write v / c (float division) and then call int(...) or math.floor(...). While math.floor works, using plain int() can be misleading if negatives were ever involved, and float division introduces unnecessary precision concerns.

return int(vowel_count / consonant_count)   # avoid: float arithmetic

Solution: Use Python's integer floor-division operator //, which directly yields the floored result without any floating-point intermediate:

return vowel_count // consonant_count

Since both counts are non-negative integers, // exactly matches the required floor(v / c) semantics.


Pitfall 4: Case Sensitivity Assumptions

Although this problem guarantees only lowercase letters, reusing this logic on mixed-case input would misclassify uppercase vowels like 'A' or 'E' as consonants because the vowel set only contains lowercase letters.

Solution: If the constraints ever change to allow uppercase, normalize with ch.lower() before the membership check:

if ch.lower() in vowels:
    vowel_count += 1

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

What's the output of running the following function using input [30, 20, 10, 100, 33, 12]?

1def fun(arr: List[int]) -> List[int]:
2    import heapq
3    heapq.heapify(arr)
4    res = []
5    for i in range(3):
6        res.append(heapq.heappop(arr))
7    return res
8
1public static int[] fun(int[] arr) {
2    int[] res = new int[3];
3    PriorityQueue<Integer> heap = new PriorityQueue<>();
4    for (int i = 0; i < arr.length; i++) {
5        heap.add(arr[i]);
6    }
7    for (int i = 0; i < 3; i++) {
8        res[i] = heap.poll();
9    }
10    return res;
11}
12
1class HeapItem {
2    constructor(item, priority = item) {
3        this.item = item;
4        this.priority = priority;
5    }
6}
7
8class MinHeap {
9    constructor() {
10        this.heap = [];
11    }
12
13    push(node) {
14        // insert the new node at the end of the heap array
15        this.heap.push(node);
16        // find the correct position for the new node
17        this.bubble_up();
18    }
19
20    bubble_up() {
21        let index = this.heap.length - 1;
22
23        while (index > 0) {
24            const element = this.heap[index];
25            const parentIndex = Math.floor((index - 1) / 2);
26            const parent = this.heap[parentIndex];
27
28            if (parent.priority <= element.priority) break;
29            // if the parent is bigger than the child then swap the parent and child
30            this.heap[index] = parent;
31            this.heap[parentIndex] = element;
32            index = parentIndex;
33        }
34    }
35
36    pop() {
37        const min = this.heap[0];
38        this.heap[0] = this.heap[this.size() - 1];
39        this.heap.pop();
40        this.bubble_down();
41        return min;
42    }
43
44    bubble_down() {
45        let index = 0;
46        let min = index;
47        const n = this.heap.length;
48
49        while (index < n) {
50            const left = 2 * index + 1;
51            const right = left + 1;
52
53            if (left < n && this.heap[left].priority < this.heap[min].priority) {
54                min = left;
55            }
56            if (right < n && this.heap[right].priority < this.heap[min].priority) {
57                min = right;
58            }
59            if (min === index) break;
60            [this.heap[min], this.heap[index]] = [this.heap[index], this.heap[min]];
61            index = min;
62        }
63    }
64
65    peek() {
66        return this.heap[0];
67    }
68
69    size() {
70        return this.heap.length;
71    }
72}
73
74function fun(arr) {
75    const heap = new MinHeap();
76    for (const x of arr) {
77        heap.push(new HeapItem(x));
78    }
79    const res = [];
80    for (let i = 0; i < 3; i++) {
81        res.push(heap.pop().item);
82    }
83    return res;
84}
85

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More