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
這道題說是讓求n個元音的全排列的個數,所謂的元音,就是 a,e,i,o,u 這五個字母。並制定了一系列的規則:a的后面只能跟e,e的后面只能跟a或i,i的后面不能跟另一個i,o的后面只能跟i或u,u的后面只能跟a。跟許多其他的求個數的題目一樣,返回的結果要對一個超大數取余。根據博主多年的刷題經驗,這種要對超大數字取余的題目,十有八九都是要用動態規划 Dynamic Programming 來做的,這道題也不例外。首先來考慮 DP 數組該如何定義,想想組成每個狀態都有哪些必要的信息,全排列的長度肯定是必要的信息之一,還有就是當前全排列最后一個位置的字母也很重要,因為題目中的規則限定了很多相連字母之間的關系,很多組合是不能出現的。這里用一個二維 DP 數組,其中 dp[i][j] 表示長度為 i+1 的全排列的最后一個字母是 vowels[j] 的個數,其中 vowels 是元音字符數組,且初始化 dp[0][j] 為1,因為只有一個字母的話並不受任何的規則約束。
接下來就是要更新 dp[i][j],用個 for 循環將i從1遍歷到n,由於元音只有5個,且各自的規則不同,所以不需要再用一個內層的 for 循環來遍歷j,而且按照各自不同的規則來分別更新。通過分析題目中的規則可知,元音a前面只能有e,i,u,用 dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][4] 來更新 dp[i][0]。元音e前面只能有a,i,用 dp[i - 1][0] + dp[i - 1][2] 來更新 dp[i][1]。元音i前面只能有e,o,用 dp[i - 1][1] + dp[i - 1][3] 來更新 dp[i][2]。元音o前面只能有i,用 dp[i - 1][2] 來更新 dp[i][3]。元音u前面只能有i,o,用 dp[i - 1][2] + dp[i - 1][3] 來更新 dp[i][4]。最后只要將所有的 dp[n-1][j] 都加起來就是所求結果,為了防止整型溢出,在所有的加的操作之后都對超大數取余,而且 dp 數組要定義成長整型的,參見代碼如下:
class Solution {
public:
int countVowelPermutation(int n) {
int res = 0, M = 1e9 + 7;
vector<char> vowels{'a', 'e', 'i', 'o', 'u'};
vector<vector<long>> dp(n, vector<long>(5));
for (int j = 0; j < 5; ++j) dp[0][j] = 1;
for (int i = 1; i < n; ++i) {
dp[i][0] = (dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][4]) % M;
dp[i][1] = (dp[i - 1][0] + dp[i - 1][2]) % M;
dp[i][2] = (dp[i - 1][1] + dp[i - 1][3]) % M;
dp[i][3] = dp[i - 1][2];
dp[i][4] = (dp[i - 1][2] + dp[i - 1][3]) % M;
}
for (int j = 0; j < 5; ++j) {
res = (res + dp[n - 1][j]) % M;
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1220
參考資料:
https://leetcode.com/problems/count-vowels-permutation/