给你一个整数 n,请返回长度为 n 、仅由元音 (a, e, i, o, u) 组成且按 字典序排列 的字符串数量。
字符串 s 按 字典序排列 需要满足:对于所有有效的 i,s[i] 在字母表中的位置总是与 s[i+1] 相同或在 s[i+1] 之前。
示例 1:
输入:n = 1
输出:5
解释:仅由元音组成的 5 个字典序字符串为 [“a”,“e”,“i”,“o”,“u”]
示例 2:
输入:n = 2
输出:15
解释:仅由元音组成的 15 个字典序字符串为
[“aa”,“ae”,“ai”,“ao”,“au”,“ee”,“ei”,“eo”,“eu”,“ii”,“io”,“iu”,“oo”,“ou”,“uu”]
注意,“ea” 不是符合题意的字符串,因为 ‘e’ 在字母表中的位置比 ‘a’ 靠后
示例 3:
输入:n = 33
输出:66045
提示:
1 <= n <= 50
法一:举例说明,当n=1时,有a、e、i、o、u 5个字符串,当n=2时,我们可以在n=1时,所有字符串的基础上做修改,具体做法是往n=1时的每个字符串前面加一个字符,a可以加到所有元音字符开头的字符串前面,e可以加到以除了a外的其他元音字符开头的字符串前面,以此类推。我们可以维护一个大小为5的数组,分别表示以a、e、i、o、u开头的字符串的数量,每次增加字符时,更新数量即可:
class Solution {
public:int countVowelStrings(int n) {// 分别表示以aeiou为开头的字符串的数量vector<int> temp = {1,1,1,1,1};for (int i = 1; i < n; ++i){// a可以放在以aeiou为开头的字符串前面,之后,以a为开头的字符串数量就是这些字符串数量之和temp[0] = temp[0] + temp[1] + temp[2] + temp[3] + temp[4];// e可以放在以eiou为开头的字符串前面,之后,以e为开头的字符串数量就是这些字符串数量之和,下同temp[1] = temp[1] + temp[2] + temp[3] + temp[4];temp[2] = temp[2] + temp[3] + temp[4];temp[3] = temp[3] + temp[4];}return accumulate(temp.begin(), temp.end(), 0);}
};
由于元音字符串的数目可以看做常量,因此此算法时间复杂度为O(n),空间复杂度为O(1)。
法二:题目等价于把n个小球放到5个盒子里,这样放到第一个盒子里的球就相当于a,第二个盒子里的球就是字符e,依此类推。问题转变为n个小球放到5个盒子里,有几种放法。这种问题的解法之一是挡板法,即把n个球直线排列形成的n-1个间隙中插挡板,有5个盒子,因此需要插4个挡板,因此放法一共有 C n − 1 4 C_{n-1}^4 Cn−14种。但这个解法隐含了每个盒子里必然有一个小球,因为两间隙之间必然会有一个小球,但根据题目,盒子可以为空。我们也不能把挡板设定为可以放在n个球的两边,因为这样做只能保证两边的盒子可以为空,而中间的盒子还是至少有1个球。一个解决方案是我们可以先借5个球,一共n+5个球,这样用挡板分完5个盒子后,再每个盒子减1个球就符合题意了,这样就可以实现每个盒子里都可以为空,因此最终结果是 C n + 4 4 C_{n+4}^4 Cn+44:
class Solution {
public:int countVowelStrings(int n) {return (n + 4) * (n + 3) * (n + 2) * (n + 1) / (4 * 3 * 2 * 1);}
};
由于元音字符串的数目可以看做常量,因此此算法时间复杂度为O(1),空间复杂度为O(1)。