难度:困难
目录
一、问题描述
这里我直接采用的LeetCode上面的问题描述。
给你一个整数 n
,请你帮忙统计一下我们可以按下述规则形成多少个长度为 n
的字符串:
- 字符串中的每个字符都应当是小写元音字母(
'a'
,'e'
,'i'
,'o'
,'u'
) - 每个元音 'a' 后面都只能跟着 'e'
- 每个元音 'e' 后面只能跟着 'a' 或者是 'i'
- 每个元音 'i' 后面 不能 再跟着另一个 'i'
- 每个元音 'o' 后面只能跟着 'i' 或者是 'u'
- 每个元音 'u' 后面只能跟着 'a'
由于答案可能会很大,所以请你返回 模 10^9 + 7
之后的结果。
下面给出示例:
二、解题思想
1.方法一
首先我想到的是,根据题目的规定每个字母共有以下情况:
- a 后面只能是e。
- e 后面只能是a、i。
- i 后面只能是a、e、o、u。
- o 后面只能是i、u。
- u 后面只能是a。
所以根据以上的情况:
- 每有一个 a 结尾的字符串,就会产生一个 e 结尾的字符串。
- 每有一个 e 结尾的字符串,就会分别产生一个 a 和 i 结尾的字符串。
- 每有一个 i 结尾的字符串,就会分别产生一个以a、e、o、u结尾的字符串。
- 每有一个 o 结尾的字符串,就会分别产生一个 i 和 u 结尾的字符串。
- 每有一个 u 结尾的字符串,就会产生一个 a 结尾的字符串。
所以编写出了以下的代码:
int countVowelPermutation(int n) {
const int mod = 1e10+7;
//a、e、i、o、u结尾的字符串总个数的个数
int a=1, e=1, i=1, o=1, u=1;
for(int j = 2;j <= n; j++){
//统计产生了多少个以a、e、i、o、u结尾的的字符串
int tail_a=0,tail_e=0,tail_i=0,tail_o=0,tail_u=0;
for(int m = 0;m < a ;m++){
tail_e++;
}
for(int m = 0;m < e ;m++){
tail_a++;tail_i++;
}
for(int m = 0;m < i ;m++){
tail_a++;tail_e++;tail_o++;tail_u++;
}
for(int m = 0;m < o ;m++){
tail_i++;tail_u++;
}
for(int m = 0;m < u ;m++){
tail_a++;
}
a=tail_a;e=tail_e;i=tail_i;o=tail_o;u=tail_u;
}
return (a+e+i+o+u)%mod;
}
上述解题思想的问题的是,求解 n 比较大的时候,就会超出时间,意思就是时间复杂度太高了,是指数级的时间复杂度。时间复杂度为。
2.方法二(动态规划)
动态规划的思想是根据前面求解的解来求解后面的解。
于是我换个方向,由往后推转变为往前推,来计算每个字母是由哪几个字母结尾的字符串生成的。可以得到以下规律:
- a 是由以e、i、u结尾的字符串生成的。
- e 是由以a、i结尾的字符串生成的。
- i 是由以e、o结尾的字符串生成的。
- o 是由以 i 结尾的字符串生成的。
- u 是由以i、o结尾的字符串生成的。
通过以上的字符规则,我们可以得到动态规划递推公式如下:
其中0、1、2、3、4分别表示 元音字母a、e、i、o、u、i,而 公式中的 i 则表示对应元音字母的个数。
因为表示的是前一个状态的对应的个数,所以可以直接采用变量表示,不需要使用数组。因此,使用变量来表示每个字母结尾的字符串对应的前一个状态的个数和现在的个数即可。
三、解题
1、判断极端情况
因为当n = 1时,只有五个元音字母所以这里我们 for循环开始要从 n= 2开始循环。
2、代码实现
int countVowelPermutation(int n) {
const int mod = 1e9+7;
//a、e、i、o、u结尾的字符串总个数的个数
long int a=1, e=1, i=1, o=1, u=1;
for(int j = 2; j<=n; j++){
//能产生多少个以a、e、i、o、u结尾的字符串
//换言之以a结尾的字符串是由 e、i、u结尾的字符串产生的 e、i、o、u也是同理
long int Tail_a = (e+i+u)%mod;
long int Tail_e = (a+i)%mod;
long int Tail_i = (e+o)%mod;
long int Tail_o = (i)%mod;
long int Tail_u = (i+o)%mod;
a = Tail_a;
e = Tail_e;
i = Tail_i;
o = Tail_o;
u = Tail_u;
}
return (a+e+i+o+u)%mod;
}
以上就是对于本题,我查看资料以及自己思考所编写出来得题解,如果有更好的方法,欢迎大家在下方留言,一起讨论。👇👇