[LeetCode] 1220. 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

這道題說是讓求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/

https://leetcode.com/problems/count-vowels-permutation/discuss/398222/Detailed-Explanation-using-Graphs-With-Pictures-O(n)

https://leetcode.com/problems/count-vowels-permutation/discuss/398173/C%2B%2B-Bottom-up-Recursive-DPs-O(n)-and-Matrix-Exponentiation-O(logn)


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM