Given an integer n, return the number of strings of length n that consist only of vowels (a, e, i, o, u) and are lexicographically sorted.
A string s is lexicographically sorted if for all valid i, s[i] is the same as or comes before s[i+1] in the alphabet.
Example 1:
Input: n = 1
Output: 5
Explanation: The 5 sorted strings that consist of vowels only are [“a”,“e”,“i”,“o”,“u”].
Example 2:
Input: n = 2
Output: 15
Explanation: The 15 sorted strings that consist of vowels only are
[“aa”,“ae”,“ai”,“ao”,“au”,“ee”,“ei”,“eo”,“eu”,“ii”,“io”,“iu”,“oo”,“ou”,“uu”].
Note that “ea” is not a valid string since ‘e’ comes after ‘a’ in the alphabet.
Example 3:
Input: n = 33
Output: 66045
5个元音[a, e, i, o, u], 每个元音可以重复使用,
用它们组成长度为n的数组,数组元素按字母表排序。
思路:
方法1:
DP
按字母表排序也就是说a后面只能是a, e, i, o, u(因为可以重复)
e后面只能是e, i, o, u,
依次类推。
下面从后往前排,也就是 i = n - 1 ~ 0
n=2时,从后往前看,现在第0位如果是a, 那么第1位就是刚刚的一位的情况[a, e, i, o, u]
所以a = a + e + i + o + u.
n = 3时,现在第0位如果是a, 后面就是刚算好的n=2的情况,后两位可以是a开头,也可以是e, i, o, u开头,
所以a = a + e + i + o + u.
简言之,就是已经算好了后面n-1位的组合情况,现在加上第0位,看总共n位的组合情况,是一种DP思想。
这里的a表示从后往前遍历时,当前位置以a开头的组合情况。
最后一位 每个字母都只有一种组合,都是1,所以从n-2开始遍历。
public int countVowelStrings(int n) {
int a, e, i, o, u;
a = e = i = o = u = 1;
for(int k = n - 2; k >= 0; k--) {
a = a + e + i + o + u;
e = e + i + o + u;
i = i + o + u;
o = o + u;
u = u;
}
return a + e + i + o + u;
}
}
方法2:
Math,隔板法。
现要求我们把元音[a, e, i, o, u]组合成长度为n的数组,
首先我们取n个东西,这n个东西可以是[a, e, i, o, u]的其中一种,不过先不管它具体是哪个,统称为O吧,
所以现在有n 个 O排在这里。
一共有5个元音,所以现在用板子把这n个O分成5段,需要4个板子。
这5段中的第一段,里面都是a,
第二段里面都是e,… ,第5段里面都是u
然后数组中有几个[a, e, i, o, u]就取决于板子放在哪个位置,
如果两个板子中间没有东西,那就是这个字母不取了。
所以n个O + 4个板子,总共有 (n + 4)个位置,
现要决定这4个板子放在哪里,
所以要从这(n+4)个位置中,抽4个位置用来放板子,这4个板子没有排列,它们是一样的,
所以板子的位置个数为
C
n
+
4
4
=
(
n
+
4
)
⋅
(
n
+
3
)
⋅
(
n
+
2
)
⋅
(
n
+
1
)
/
4
!
C_{n+4}^{4} = (n+4)\cdot (n+3)\cdot (n+2)\cdot (n+1) / 4!
Cn+44=(n+4)⋅(n+3)⋅(n+2)⋅(n+1)/4!
public int countVowelStrings(int n) {
return (n+4) * (n+3) * (n+2) * (n+1) / 24;
}