方法一:动态规划
思路与算法
状态表示:dp[i][j] 表示长度 i + 1 的以元音字母 j 对应序号结尾的按字典序排序的字符串数量
初始状态:dp[0][j] = 1,只有一个字符
状态方程:
dp[i][j] = 1, i = 0
dp[i][j] = Sum(j, k = 0)dp[i - 1][k], i > 0
因为 dp[i] 只与 dp[i - 1] 有关,而且 dp[i][j] 是 dp[i][k] 的前缀和,因此可以使用一维数组存储。
代码
class Solution {
public int countVowelStrings(int n) {
int[] dp = new int[5];
Arrays.fill(dp, 1);
for (int i = 1; i < n; i++) {
for (int j = 1; j < 5; j++) {
dp[j] += dp[j - 1];
}
}
return Arrays.stream(dp).sum();
}
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)
方法二:组合数学
思路与算法
5 个元音第一次出现的位置按照 0 <= ia <= ie <= ii <= io <= iu <= n 排列。
作以下转换:
ie’ = ie
ii’ = ii + 1
io’ = io + 2
iu’ = iu + 3
相当于 0 <= ia < ie’ < ii’ < io’ < iu’ <= n + 3,从 0 ~ n + 3 总共 n + 4 个数选择 4 个位置放 e、i、o、u,结果等于组合 C(4)(n + 4)。
代码
class Solution {
public int countVowelStrings(int n) {
// C(4)(n+4)
return (n + 4) * (n + 3) * (n + 2) * (n + 1) / 24;
}
}
复杂度分析
时间复杂度:O(1)
空间复杂度:O(1)