{x}
blog image

Count Vowels Permutation

Given an integer n, your task is to count how many strings of length n can be formed under the following rules:

  • Each character is a lower case vowel ('a', 'e', 'i', 'o', 'u')
  • Each vowel 'a' may only be followed by an 'e'.
  • Each vowel 'e' may only be followed by an 'a' or an 'i'.
  • Each vowel 'i' may not be followed by another 'i'.
  • Each vowel 'o' may only be followed by an 'i' or a 'u'.
  • Each vowel 'u' may only be followed by an 'a'.

Since the answer may be too large, return it modulo 10^9 + 7.

 

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

Solution Explanation for LeetCode 1220: Count Vowels Permutation

This problem asks to count the number of strings of length n formed using only lowercase vowels ('a', 'e', 'i', 'o', 'u') while adhering to specific constraints on vowel successions. We'll explore two efficient solutions: Dynamic Programming and Matrix Exponentiation.

Solution 1: Dynamic Programming

This approach uses dynamic programming to iteratively build up the count of valid strings.

Approach:

  1. State: We define f[i] as the number of strings of length k ending with the i-th vowel (where 'a' is 0, 'e' is 1, etc.). Initially, for strings of length 1, f[i] = 1 for all vowels.

  2. Transitions: We create a transition matrix based on the allowed vowel successions:

    a -> e
    e -> a, i
    i -> a, e, o, u
    o -> i, u
    u -> a 
    

    This implies that to find the number of strings of length k+1 ending in vowel i, we sum up the number of strings of length k ending in vowels that can precede i. For example, the number of strings of length k+1 ending in 'a' (g[0]) is the sum of strings of length k ending in 'e', 'i', 'u'.

  3. Iteration: We iterate n-1 times, updating f in each iteration to represent the counts for the next length. We use a temporary array g to store the counts for the next length to avoid overwriting f prematurely.

  4. Result: Finally, the total count of valid strings of length n is the sum of all elements in the final f array, taken modulo 10^9 + 7 to handle potential overflow.

Time Complexity: O(n), as we iterate n-1 times. The operations within each iteration are constant time.

Space Complexity: O(1), as we only store a constant number of arrays (f and g). The space used is independent of n.

Solution 2: Matrix Exponentiation (for faster computation with large n)

When n is very large, the dynamic programming approach can become slow. Matrix exponentiation offers a significant speedup.

Approach:

  1. Transition Matrix: We represent the allowed vowel transitions using a 5x5 matrix A, where A[i][j] = 1 if vowel j can follow vowel i, and 0 otherwise.

  2. Matrix Power: The number of valid strings of length n can be found by raising the transition matrix A to the power of n-1 and then summing up the elements of the resulting matrix's first row. This is because matrix multiplication naturally captures the allowed transitions.

  3. Efficient Exponentiation: We use binary exponentiation (or repeated squaring) to compute A^(n-1) efficiently in O(log n) time.

Time Complexity: O(log n * C³), where C is the number of vowels (5 in this case). The dominant factor is the matrix exponentiation, which has a complexity of O(log n) matrix multiplications, each taking O(C³).

Space Complexity: O(C²), the space used to store the transition matrix and intermediate results during exponentiation.

Code Examples (Python):

Solution 1 (Dynamic Programming):

def countVowelPermutation(n):
    mod = 10**9 + 7
    f = [1] * 5  # Initial counts for strings of length 1
    for _ in range(n - 1):
        g = [0] * 5
        g[0] = (f[1] + f[2] + f[4]) % mod  # a -> e, i, u
        g[1] = (f[0] + f[2]) % mod        # e -> a, i
        g[2] = (f[1] + f[3]) % mod        # i -> a, e, o, u
        g[3] = f[2] % mod                  # o -> i, u
        g[4] = (f[2] + f[3]) % mod        # u -> a
        f = g
    return sum(f) % mod

Solution 2 (Matrix Exponentiation): Requires a library for matrix operations (like NumPy).

import numpy as np
 
def countVowelPermutation(n):
    mod = 10**9 + 7
    A = np.array(
        [
            [0, 1, 0, 0, 0],
            [1, 0, 1, 0, 0],
            [1, 1, 0, 1, 1],
            [0, 0, 1, 0, 1],
            [1, 0, 0, 0, 0],
        ]
    )
    res = np.linalg.matrix_power(A, n - 1)  #Efficient matrix power
    return np.sum(res[0]) % mod
 

Choose the solution that best fits your needs. Dynamic programming is simpler but may be slower for very large n, while matrix exponentiation is faster for large n but slightly more complex to implement. Remember that the code examples can be easily adapted to other programming languages.