持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
LeetCode每日一题打卡专栏正式启动!不出意外将日更LeetCode的每日一题,敬请期待。
1220:统计元音字母序列的数目
题意
给你一个整数 n,请你帮忙统计一下我们可以按下述规则形成多少个长度为 n 的字符串:
- 字符串中的每个字符都应当是小写元音字母('a', 'e', 'i', 'o', 'u')
- 每个元音 'a' 后面都只能跟着 'e'
- 每个元音 'e' 后面只能跟着 'a' 或者是 'i'
- 每个元音 'i' 后面 不能 再跟着另一个 'i'
- 每个元音 'o' 后面只能跟着 'i' 或者是 'u'
- 每个元音 'u' 后面只能跟着 'a'
由于答案可能会很大,所以请你返回 模 10^9 + 7 之后的结果。
提示:
1 <= n <= 2 * 10^4
示例1:
输入:n = 1 输出:5 解释:所有可能的字符串分别是:"a", "e", "i" , "o" 和 "u"。
示例2:
输入:n = 2 输出:10 解释:所有可能的字符串分别是:"ae", "ea", "ei", "ia", "ie", "io", "iu", "oi", "ou" 和 "ua"。
示例3:
输入:n = 5 输出:68
题解:dp
通过题意可以知道:
- 以a结尾的话前面只能是u,i,e
- 以e结尾的话前面只能是a,i
- 以i结尾的话前面只能是e,o
- 以o结尾的话前面只能是i
- 以u结尾的话前面只能是i,o
于是我们最终的结果可以视为:n个字符分别以a,e,i,o,u结尾的个数总和。
联想到dp,于是:前个字符其中以字符结尾能满足题意的字符串个数
个人习惯dp数组下标从1开始:于是j=1,2,3,4,5分别表示为a,e,i,o,u
于是状态转移方程为:
具体代码如下:
C++代码:
class Solution {
public:
int dp[20010][6];
int mod=1e9+7;
int countVowelPermutation(int n) {
int ans=0;
for(int i=1;i<=5;i++) dp[1][i]=1;
for(int i=2;i<=n;i++){
dp[i][1]=((dp[i-1][2]+dp[i-1][3])%mod+dp[i-1][5])%mod; //a结尾的话前面只能是u,i,e;后面同理
dp[i][2]=(dp[i-1][1]+dp[i-1][3])%mod;
dp[i][3]=(dp[i-1][2]+dp[i-1][4])%mod;
dp[i][4]=dp[i-1][3]%mod;
dp[i][5]=(dp[i-1][3]+dp[i-1][4])%mod;
}
for(int i=1;i<=5;i++) ans=(ans+dp[n][i])%mod;
return ans;
}
};
Java代码:
class Solution {
public int countVowelPermutation(int n) {
int dp[][]=new int[n+1][6]; //dp[i][j]:前i个字符其中以字符j结尾组成满足题意的个数
int mod=(int)1e9+7;
int ans=0;
//初始化
for(int i=1;i<=5;i++) dp[1][i]=1;
for(int i=2;i<=n;i++){
dp[i][1]=((dp[i-1][2]+dp[i-1][3])%mod+dp[i-1][5])%mod; //a结尾的话前面只能是u,i,e;后面同理
dp[i][2]=(dp[i-1][1]+dp[i-1][3])%mod;
dp[i][3]=(dp[i-1][2]+dp[i-1][4])%mod;
dp[i][4]=dp[i-1][3]%mod;
dp[i][5]=(dp[i-1][3]+dp[i-1][4])%mod;
}
for(int i=1;i<=5;i++) ans=(ans+dp[n][i])%mod;
return ans;
}
}