Count Vowels Permutation

Updated on 16 May, 2025
Count Vowels Permutation header image

Problem Statement

Given an integer n, the problem asks to determine the number of strings of length n that can be constructed using the vowels: 'a', 'e', 'i', 'o', 'u'. Each vowel has specific rules concerning which vowels can follow it in the string:

  • 'a' can only be followed by 'e'.
  • 'e' can be followed by 'a' or 'i'.
  • 'i' can be followed by any vowel except 'i' itself.
  • 'o' can be followed by 'i' or 'u'.
  • 'u' can be followed by 'a'.

These rules significantly influence the string construction, making it a constrained combinatorial problem. Given the potential size of the output, it must be returned modulo (10^9 + 7) to prevent overflow issues.

Examples

Example 1

Input:

n = 1

Output:

5

Explanation:

All possible strings are: "a", "e", "i" , "o" and "u".

Example 2

Input:

n = 2

Output:

10

Explanation:

All possible strings are: "ae", "ea", "ei", "ia", "ie", "io", "iu", "oi", "ou" and "ua".

Example 3

Input:

n = 5

Output:

68

Constraints

  • 1 <= n <= 2 * 10^4

Approach and Intuition

To solve the problem of counting the number of valid strings of length n under the given constraints, we need to think in terms of dynamic programming or combinatorial counting with transition rules based on the established sequence-building restrictions:

  1. Initialization: Consider the base scenario when n is 1. Here, each of the vowels 'a', 'e', 'i', 'o', 'u' are valid strings in themselves. Therefore, there are 5 possible strings when n equals 1.

  2. Recursive Relation Development: For lengths greater than one, determine the number of ways to form sequences of length n based on sequences of length n-1. Develop a relationship based on permitted transitions:

    • If a string of length n ends in 'a', the string of length n-1 could have ended in 'e' or 'u' based on the rules specified.
    • If it ends in 'e', it could have been 'a' or 'i' previously.
    • For an ending 'i', the preceding character could have been 'e', 'o', or 'u'.
    • Similarly, develop transition counts for strings ending in 'o' and 'u'.
  3. Dynamic Programming Table Construction: Use dp (a dynamic programming table) where dp[i][v] represents the number of valid strings of length i that end with vowel v. Intuitively fill this table based on n and using transitions defined:

    • The recursive relations will allow you to populate dp table row by row for each vowel ending.
  4. Result Calculation: Finally, for the desired length n, the result would be the sum of all strings ending in any vowel calculated from the dp table, i.e., sum of all dp[n][vowel]. Return this result modulo (10^9 + 7).

This approach ensures that each position in the string is built upon the valid preceding configurations, satisfying the transition constraints optimally.

Solutions

  • Java
  • Python
java
class Solution {
    private long[][] dp;
    private final int MODULO = 1000000007;

    public int countVowelPermutation(int length) {
        dp = new long[length][5];
        long sum = 0;
        for (int i = 0; i < 5; i++) {
            sum = (sum + calculatePermutations(length - 1, i)) % MODULO;
        }
        return (int)sum;
    }

    private long calculatePermutations(int len, int vowelIndex) {
        if (dp[len][vowelIndex] != 0) return dp[len][vowelIndex];
        if (len == 0) {
            dp[len][vowelIndex] = 1;
        } else {
            if (vowelIndex == 0) {
                dp[len][vowelIndex] = (calculatePermutations(len - 1, 1) + calculatePermutations(len - 1, 2) + calculatePermutations(len - 1, 4)) % MODULO;
            } else if (vowelIndex == 1) {
                dp[len][vowelIndex] = (calculatePermutations(len - 1, 0) + calculatePermutations(len - 1, 2)) % MODULO;
            } else if (vowelIndex == 2) {
                dp[len][vowelIndex] = (calculatePermutations(len - 1, 1) + calculatePermutations(len - 1, 3)) % MODULO;
            } else if (vowelIndex == 3) {
                dp[len][vowelIndex] = calculatePermutations(len - 1, 2);
            } else if (vowelIndex == 4) {
                dp[len][vowelIndex] = (calculatePermutations(len - 1, 2) + calculatePermutations(len - 1, 3)) % MODULO;
            }
        }
        return dp[len][vowelIndex];
    }
}

The Java solution presented is designed to solve the problem of counting the number of valid vowel permutations of a given length, adhering to specific rules on how vowels can follow each other. The solution utilizes dynamic programming to efficiently count permutation possibilities.

  • Begin with initializing a 2D array dp to store the results of subproblems. This array helps in avoiding the recomputation of the same problems.
  • Define a constant MODULO to ensure the result remains within the bounds of typical integer ranges, specifically set to 1000000007 for handling large numbers.
  • Implement the countVowelPermutation method which initializes the total count and iterates over each vowel, leveraging the calculatePermutations method to compute the number of permutations starting with each vowel.
  • In the calculatePermutations method:
    • Check if the result for the current state (len, vowelIndex) has previously been computed and stored in dp; if so, return the stored result.
    • Base case consideration for len == 0, which signifies the starting point of counting, set the corresponding dp value to 1.
    • For each vowel, compute the valid subsequent permutations by recursively calling calculatePermutations for valid vowel sequences according to predefined rules (e.g., after 'a' can only come 'e', 'i', or 'u').
    • Use modulo operation to maintain results in a manageable range and prevent overflow.
  • The permutations are summed and returned as the answer for the given length.

This approach ensures an optimal solution by reducing the time complexity via memoization, which stores intermediate results in the dp table and reuses them. The recursive method combined with dynamic programming effectively tackles the exponential nature of the problem, allowing it to handle larger inputs efficiently.

python
class Solution:
    def calculateVowelPermutations(self, length: int) -> int:
        MODULO = 1000000007
        @functools.cache
        def compute_vowel_permutations(index, current_vowel):
            count = 1
            if index > 1:
                if current_vowel == 'a':
                    count = (compute_vowel_permutations(index - 1, 'e') + compute_vowel_permutations(index - 1, 'i') + compute_vowel_permutations(index - 1, 'u')) % MODULO
                elif current_vowel == 'e':
                    count = (compute_vowel_permutations(index - 1, 'a') + compute_vowel_permutations(index - 1, 'i')) % MODULO
                elif current_vowel == 'i':
                    count = (compute_vowel_permutations(index - 1, 'e') + compute_vowel_permutations(index - 1, 'o')) % MODULO
                elif current_vowel == 'o':
                    count = compute_vowel_permutations(index - 1, 'i')
                else:
                    count = (compute_vowel_permutations(index - 1, 'i') + compute_vowel_permutations(index - 1, 'o')) % MODULO
            return count

        return sum(compute_vowel_permutations(length, vowel) for vowel in 'aeiou') % MODULO

This Python solution addresses the problem of counting vowel permutations for a given length using dynamic programming and memoization. The implementation encapsulates its logic within a calculateVowelPermutations method of the Solution class. Here, a recursive helper function compute_vowel_permutations is defined with caching via functools.cache to optimize repeated computations.

Here's a brief breakdown of how the solution works:

  • A base modulus MODULO is set at 1000000007 to handle large numbers and avoid overflow.
  • The recursive function compute_vowel_permutations computes permutations based on the previous character's possible transitions:
    • 'a' can be followed by 'e', 'i', or 'u'.
    • 'e' can be followed by 'a' or 'i'.
    • 'i' can transition to either 'e' or 'o'.
    • 'o' only transitions to 'i'.
    • 'u' transitions to 'i' or 'o'.
  • To compute permutations for a particular length and starting vowel, the function checks if the string length is greater than 1 and then recursively determines the count of permutations from the previous index for valid preceding vowels, applying modulo operations to handle large results.
  • The entry point of the function aggregates results from all possible starting vowels ('aeiou') to get the total number of permutations of the specified length.

Assure correct and efficient calculations of the permutation counts by ensuring that memoization effectively reduces the computation time, especially for larger string lengths.

Comments

No comments yet.