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
Solutions
Solution 1: Dynamic Programming
Thinking
Vowel strings of length \(n\) obey adjacency rules. \(n\) reaches \(2\times 10^4\), so we cannot list strings. It suffices to count strings by last vowel: each letter has a fixed set of legal predecessors.
An array \(f\) of length \(5\) stores counts by ending letter; we roll it \(n-1\) times by those predecessors. Only the previous length is needed. We reduce modulo \(10^9+7\).
Based on the problem description, we can list the possible subsequent vowels for each vowel:
a[e]
e[a|i]
i[a|e|o|u]
o[i|u]
u[a]
From this, we can deduce the possible preceding vowels for each vowel:
[e|i|u]a
[a|i]e
[e|o]i
[i]o
[i|o]u
We define \(f[i]\) as the number of strings of the current length ending with the \(i\)-th vowel. If the length is \(1\), then \(f[i]=1\).
When the length is greater than \(1\), we define \(g[i]\) as the number of strings of the current length ending with the \(i\)-th vowel. Then \(g[i]\) can be derived from \(f\), that is:
The final answer is \(\sum_{i=0}^{4}f[i]\). Note that the answer may be very large, so we need to take the modulus of \(10^9+7\).
The time complexity is \(O(n)\), and the space complexity is \(O(C)\). Here, \(n\) is the length of the string, and \(C\) is the number of vowels. In this problem, \(C=5\).
/** * @param {number} n * @return {number} */varcountVowelPermutation=function(n){constmod=1e9+7;constf=Array(5).fill(1);for(leti=1;i<n;++i){constg=Array(5).fill(0);g[0]=(f[1]+f[2]+f[4])%mod;g[1]=(f[0]+f[2])%mod;g[2]=(f[1]+f[3])%mod;g[3]=f[2];g[4]=(f[2]+f[3])%mod;f.splice(0,5,...g);}returnf.reduce((a,b)=>(a+b)%mod);};
Solution 2: Matrix Exponentiation to Accelerate Recursion
Thinking
Solution 1 spends \(O(n)\) constant-size updates. The five-state recurrence is a linear map. Encoded as a \(5\times 5\) matrix, exponentiation by squaring yields the \(n\)-th vector in \(O(\log n)\) multiplications, which helps for larger \(n\).
The time complexity is \(O(C^3 \times \log n)\), and the space complexity is \(O(C^2)\). Here, \(C\) is the number of vowels. In this problem, \(C=5\).