- 这是我参与 2022 首次更文挑战的第 1 天,活动详情查看:2022首次更文挑战
1、题目描述(统计元音字母序列的数目)
- 给你一个整数
n,请你帮忙统计一下我们可以按下述规则形成多少个长度为n的字符串,当答案很大的时候请返回模10^9 + 7之后的结果。
- 字符串中的每个字符都应当是小写元音字母(
'a','e','i','o','u') - 每个元音
'a'后面都只能跟着'e' - 每个元音
'e'后面只能跟着'a'或者是'i' - 每个元音
'i'后面 不能 再跟着另一个'i' - 每个元音
'o'后面只能跟着'i'或者是'u' - 每个元音
'u'后面只能跟着'a'
2、方法与思路
输入: n = 1
输出: 5
解释: 所有可能的字符串分别是:"a", "e", "i" , "o" 和 "u"。
输入:n = 2
输出:10
解释:所有可能的字符串分别是:"ae", "ea", "ei", "ia", "ie", "io", "iu", "oi", "ou" 和 "ua"。
我们从上面的题目描述和例题输入和输出可以直观地看出,第 n 个字符与第 n - 1 个字符有关。第一时间想到的可能是列出状态转移方程,然后用常规的动态规划方法去做。但是这道题目的过程分析不是很复杂,所以我们有更简单的方法。
- 我们把以每种字符结尾的字符串数进行分类统计。
- 长度为 n 的有效字符串 与 长度为 n - 1 的有效字符串相关,例如:长度为 n - 1 且以 e 结尾的字符串,可以在它的后面加上字符 a 或者 i 分裂成两个长度为 n 的有效字符串;长度为 n - 1 且以 o 结尾的字符串,可以在它的后面加上字符 i 或者 u 分裂成两个长度为 n 的有效字符串。当单个字符串的个数超过最大阈值时可以对单个进行取模,正确性显然。
- 所以我们只要统计前一个状态以每种字符结尾的字符串数量就可以了。
3、题解代码 & 注释
public int countVowelPermutation(int n) {
long A = 1; // 记录元音字母 a 的初始状态,下同。
long E = 1;
long I = 1;
long O = 1;
long U = 1;
long MOD = (long)1e9 + 7;
while (--n > 0) {
long a = A; // 暂存以 a 字母结尾的字符串的数量,下同。
long e = E;
long i = I;
long o = O;
long u = U;
A = (e + i + u) % MOD; // 前以状态以 e i u 结尾的字符串,都可在其词尾加上 a 有效,下同。
E = (a + i) % MOD;
I = (e + o) % MOD;
O = i % MOD;
U = (i + o) % MOD;
}
return (int)((A + E + I + O + U) % MOD);
}