一起刷力扣之【1220. 统计元音字母序列的数目】

224 阅读3分钟

这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战

题目

给你一个整数 n,请你帮忙统计一下我们可以按下述规则形成多少个长度为 n 的字符串:

字符串中的每个字符都应当是小写元音字母('a', 'e', 'i', 'o', 'u'

  • 每个元音 'a' 后面都只能跟着 'e'
  • 每个元音 'e' 后面只能跟着 'a' 或者是 'i'
  • 每个元音 'i' 后面 不能 再跟着另一个 'i'
  • 每个元音 'o' 后面只能跟着 'i' 或者是 'u'
  • 每个元音 'u' 后面只能跟着 'a' 由于答案可能会很大,所以请你返回 模 10^9 + 7 之后的结果。

示例

输入: n = 1
输出: 5
解释: 所有可能的字符串分别是:"a", "e", "i" , "o""u"
输入:n = 2
输出:10
解释:所有可能的字符串分别是:"ae", "ea", "ei", "ia", "ie", "io", "iu", "oi", "ou""ua"
输入: n = 5
输出: 68

提示

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

解题思路

动态规划

这道题咋一看有点像有限状态机,每一个元音后面都有对应的限制,只能跟着符合条件的字母,但是当使用有限状态机的解法来解题时会发现有些别扭,该题最终要求的是根据规则可以形成多少个字符串,而不是要判断是否符合条件,因此我们需要在其基础上做个改进。

定义一个二维dp数组,用来保存每一个长度,各个元音字母分别有多少组合。

  • n == 1时,分别自有元音字母本身,所以需要将对应的元素填充为1
  • 根据规则,当长度增加是,对应的元音字母组合也需要增加。 但是这里需要注意的是不能直接照着规则,例如:元音 'a' 后面都只能跟着 'e',不能写成dp[i][a] += dp[i - 1][e],这么写的话顺序就反过来了。

我们需要看的是后面的条件,字母'e''a','i'这两个字母的后缀条件,那么就可以理解为'e'前面必定为'a'或者'i',那么在字母'e'前,则可能有'a'种情况加上'i'种情况,因此我们需要加上两者的和,即可求得当前字母所有的排列。

最后再对五个字母进行求和操作即可得出最终结果。

class Solution {
    public int countVowelPermutation(int n) {
        final int MOD = (int)1e9+7;
        long[][] dp = new long[n][5];
        Arrays.fill(dp[0], 1);
        
        for(int i = 1; i < n; ++i){
            dp[i][0] += (dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][4]) % MOD;
            dp[i][1] += (dp[i - 1][0] + dp[i - 1][2]) % MOD;
            dp[i][2] += (dp[i - 1][1] + dp[i - 1][3]) % MOD;
            dp[i][3] += (dp[i - 1][2]) % MOD;
            dp[i][4] += (dp[i - 1][2] + dp[i - 1][3])% MOD;
        }

        long sum = 0L;
        for(int i = 0; i < 5; ++i){
            sum += dp[n - 1][i] ;
        }

        return (int)(sum % MOD);
    }
}