Balance Consonant and Vowels Ratio

Last Updated : 11 Jul, 2025

You are given an array of strings arr[], where each string contains only lowercase English letters. Count the number of contiguous subarrays (i.e., one or more consecutive strings from arr[]) whose concatenation forms a balanced string.

Note: A string is considered balanced if it contains an equal number of vowels and consonants.

Examples:

Input: arr[] = ["aeio", "aa", "bc", "ot", "cdbd"]
Output: 4
Explanation: arr[0...4], arr[1...2], arr[1...3], arr[3...3] are the balanced substrings with equal consonants and vowels.

Input: arr[] = ["ab", "be"]
Output: 3
Explanation: arr[0..0], arr[0..1], arr[1..1] are the balanced substrings with equal consonants and vowels.

Input: arr[] = ["tz", "gfg", "ae"]
Output: 0
Explanation: There is no such balanced substring present in arr[] with equal consonants and vowels.

Try It Yourself
redirect icon

[Naive Approach] Generate all possible subarrays

Try all possible contiguous subarrays of arr[], concatenate the strings within each subarray, and count the number of vowels and consonants in the resulting string. If the counts are equal, the string is considered balanced, and we increment our result.

C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;

// Helper to check if a character is a vowel
bool isVowel(char ch) {
    return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}

// Function to count balanced subarrays
int countBalanced(vector<string>& arr) {
    int n = arr.size();
    int res = 0;

    // Try all subarrays
    for (int i = 0; i < n; i++) {
        string s = "";
        
        for (int j = i; j < n; j++) {
            s += arr[j];
            
            // vowel and consonant counts
            int v = 0, c = 0; 

            // Count vowels and consonants
            for (char ch : s) {
                if (isVowel(ch)) v++;
                else c++;
            }

            // If balanced, increase count
            if (v == c) res++;
        }
    }

    return res;
}

int main() {
    vector<string> arr = {"aeio", "aa", "bc", "ot", "cdbd"};
    cout << countBalanced(arr) << endl;

    return 0;
}
Java
public class GfG {

    // Helper to check if a character is a vowel
    public static boolean isVowel(char ch) {
        return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
    }

    // Function to count balanced subarrays
    public static int countBalanced(String[] arr) {
        int n = arr.length;
        int res = 0;

        for (int i = 0; i < n; i++) {
            String s = "";

            for (int j = i; j < n; j++) {
                s += arr[j];
                int v = 0, c = 0;

                // Count vowels and consonants
                for (char ch : s.toCharArray()) {
                    if (isVowel(ch)) v++;
                    else c++;
                }

                if (v == c) res++;
            }
        }

        return res;
    }

    public static void main(String[] args) {
        String[] arr = {"aeio", "aa", "bc", "ot", "cdbd"};
        System.out.println(countBalanced(arr));
    }
}
Python
# Helper to check if a character is a vowel
def isVowel(ch):
    return ch in 'aeiou'

# Function to count balanced subarrays
def countBalanced(arr):
    n = len(arr)
    res = 0

    for i in range(n):
        s = ''
        for j in range(i, n):
            s += arr[j]
            v = c = 0

            # Count vowels and consonants
            for ch in s:
                if isVowel(ch):
                    v += 1
                else:
                    c += 1

            if v == c:
                res += 1

    return res

if __name__ == "__main__":
    arr = ["aeio", "aa", "bc", "ot", "cdbd"]
    print(countBalanced(arr))
C#
using System;

class GfG
{
    // Helper to check if a character is a vowel
    static bool isVowel(char ch) {
        return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
    }

    // Function to count balanced subarrays
    static int countBalanced(string[] arr)
    {
        int n = arr.Length;
        int res = 0;

        for (int i = 0; i < n; i++)
        {
            string s = "";
            for (int j = i; j < n; j++)
            {
                s += arr[j];
                int v = 0, c = 0;

                // Count vowels and consonants
                foreach (char ch in s) {
                    if (isVowel(ch)) v++;
                    else c++;
                }

                if (v == c) res++;
            }
        }

        return res;
    }

    static void Main()
    {
        string[] arr = { "aeio", "aa", "bc", "ot", "cdbd" };
        Console.WriteLine(countBalanced(arr));
    }
}
JavaScript
// Helper to check if a character is a vowel
function isVowel(ch) {
    return 'aeiou'.includes(ch);
}

// Function to count balanced subarrays
function countBalanced(arr) {
    let n = arr.length;
    let res = 0;

    for (let i = 0; i < n; i++) {
        let s = "";
        for (let j = i; j < n; j++) {
            s += arr[j];
            let v = 0, c = 0;
            
            // Count vowels and consonants
            for (let ch of s) {
                if (isVowel(ch)) v++;
                else c++;
            }

            if (v === c) res++;
        }
    }

    return res;
}

// Driver Code
const arr = ["aeio", "aa", "bc", "ot", "cdbd"];
console.log(countBalanced(arr));

Output
4

Time Complexity: O(nÂē * l), where n is the number of strings and l is the total length of all strings combined, because for each of the O(nÂē) subarrays, all characters are concatenated and scanned.
Space Complexity: O(l), where l is the length of the longest possible concatenated string, used by the temporary string s.

[Expected Approach] Using Hash Map

Assign each string a net score: +1 for every vowel and -1 for every consonant. Compute the prefix sum of these scores across the array. If the same prefix sum appears more than once, the subarray between those indices has equal vowels and consonants. Use a hash map to count the frequency of each prefix sum during traversal. Add the frequency of the current prefix sum to the result before updating it.

C++
#include <iostream>
#include <vector>
#include <unordered_map>
#include <string>
using namespace std;

// Function to check if a character is a vowel
bool isVowel(char ch) {
    return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}

// Function to count the number of balanced subarrays
int countBalanced(vector<string>& arr) {
    int n = arr.size();
    int res = 0;
    int prefix = 0;

    // Map to store frequency of prefix sums
    unordered_map<int, int> freq;

    // Initial prefix sum is 0 
    //(empty prefix is considered balanced)
    freq[0] = 1;

    // Traverse the array of strings
    for (int i = 0; i < n; i++) {
        int score = 0;

        // Calculate net score of current 
        // string: +1 for vowel, -1 for consonant
        for (char ch : arr[i]) {
            if (isVowel(ch)) score++;
            else score--;
        }

        // Update the running prefix sum
        prefix += score;

        // If this prefix sum has been seen before, 
        // then the subarray between previous and 
        // current prefix is balanced
        res += freq[prefix];

        // Increment the frequency of this prefix sum
        freq[prefix]++;
    }

    return res;
}

int main() {
    vector<string> arr = {"aeio", "aa", "bc", "ot", "cdbd"};

    cout << countBalanced(arr) << endl;

    return 0;
}
Java
import java.util.Map;
import java.util.HashMap;
import java.util.Arrays;

public class GfG {

    // Function to check if a character is a vowel
    public static boolean isVowel(char ch) {
        return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
    }

    // Function to count the number of balanced subarrays
    public static int countBalanced(String[] arr) {
        int n = arr.length;
        int res = 0;
        int prefix = 0;

        // Map to store frequency of prefix sums
        Map<Integer, Integer> freq = new HashMap<>();

        // Initial prefix sum is 0 (empty prefix is considered balanced)
        freq.put(0, 1);

        // Traverse the array of strings
        for (int i = 0; i < n; i++) {
            int score = 0;

            // Calculate net score of current 
            // string: +1 for vowel, -1 for consonant
            for (char ch : arr[i].toCharArray()) {
                if (isVowel(ch)) score++;
                else score--;
            }

            // Update the running prefix sum
            prefix += score;

            // If this prefix sum has been seen before, 
            // then the subarray between previous and 
            // current prefix is balanced
            res += freq.getOrDefault(prefix, 0);

            // Increment the frequency of this prefix sum
            freq.put(prefix, freq.getOrDefault(prefix, 0) + 1);
        }

        return res;
    }

    public static void main(String[] args) {
        String[] arr = {"aeio", "aa", "bc", "ot", "cdbd"};
        System.out.println(countBalanced(arr));
    }
}
Python
from collections import defaultdict

# Function to check if a character is a vowel
def isVowel(ch):
    return ch in 'aeiou'

# Function to count the number of balanced subarrays
def countBalanced(arr):
    n = len(arr)
    res = 0
    prefix = 0

    # Map to store frequency of prefix sums
    freq = defaultdict(int)

    # Initial prefix sum is 0 (empty prefix is considered balanced)
    freq[0] = 1

    # Traverse the array of strings
    for i in range(n):
        score = 0

        # Calculate net score of current 
        # string: +1 for vowel, -1 for consonant
        for ch in arr[i]:
            if isVowel(ch):
                score += 1
            else:
                score -= 1

        # Update the running prefix sum
        prefix += score

        # If this prefix sum has been seen before, 
        # then the subarray between previous and 
        # current prefix is balanced
        res += freq[prefix]

        # Increment the frequency of this prefix sum
        freq[prefix] += 1

    return res

if __name__ == "__main__":
    arr = ["aeio", "aa", "bc", "ot", "cdbd"]
    print(countBalanced(arr))
C#
using System;
using System.Collections.Generic;

class GfG
{
    // Function to check if a character is a vowel
    static bool isVowel(char ch)
    {
        return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
    }

    // Function to count the number of balanced subarrays
    static int countBalanced(string[] arr)
    {
        int n = arr.Length;
        int res = 0;
        int prefix = 0;

        // Map to store frequency of prefix sums
        Dictionary<int, int> freq = new Dictionary<int, int>();

        // Initial prefix sum is 0 (empty prefix is considered balanced)
        freq[0] = 1;

        // Traverse the array of strings
        for (int i = 0; i < n; i++)
        {
            int score = 0;

            // Calculate net score of current 
            // string: +1 for vowel, -1 for consonant
            foreach (char ch in arr[i])
            {
                if (isVowel(ch)) score++;
                else score--;
            }

            // Update the running prefix sum
            prefix += score;

            // If this prefix sum has been seen before, 
            // then the subarray between previous and 
            // current prefix is balanced
            if (freq.ContainsKey(prefix))
                res += freq[prefix];

            // Increment the frequency of this prefix sum
            if (!freq.ContainsKey(prefix))
                freq[prefix] = 0;
            freq[prefix]++;
        }

        return res;
    }

    static void Main()
    {
        string[] arr = { "aeio", "aa", "bc", "ot", "cdbd" };
        Console.WriteLine(countBalanced(arr));
    }
}
JavaScript
// Function to check if a character is a vowel
function isVowel(ch) {
    return 'aeiou'.includes(ch);
}

// Function to count the number of balanced subarrays
function countBalanced(arr) {
    let n = arr.length;
    let res = 0;
    let prefix = 0;

    // Map to store frequency of prefix sums
    const freq = new Map();

    // Initial prefix sum is 0 (empty prefix is considered balanced)
    freq.set(0, 1);

    // Traverse the array of strings
    for (let i = 0; i < n; i++) {
        let score = 0;

        // Calculate net score of current 
        // string: +1 for vowel, -1 for consonant
        for (let ch of arr[i]) {
            if (isVowel(ch)) score++;
            else score--;
        }

        // Update the running prefix sum
        prefix += score;

        // If this prefix sum has been seen before, 
        // then the subarray between previous and 
        // current prefix is balanced
        res += freq.get(prefix) || 0;

        // Increment the frequency of this prefix sum
        freq.set(prefix, (freq.get(prefix) || 0) + 1);
    }

    return res;
}

// Driver Code
const arr = ["aeio", "aa", "bc", "ot", "cdbd"];
console.log(countBalanced(arr));

Time Complexity: O(n * l), where n is the number of strings and l is the average length of each string, since each character in all strings is processed once.
Space Complexity: O(n), due to the prefix sum frequency map which can store up to n unique prefix values.

Comment