Input: n =1Output: 5Explanation: The 5 sorted strings that consist of vowels only are `["a","e","i","o","u"].`
Example 2:
1
2
3
4
5
6
7
Input:
n =2Output:
15Explanation: 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.
Generate all possible strings of length n using vowels, ensuring each character is not less than the previous one (to maintain lexicographical order). This is a classic backtracking problem where we try all valid choices at each step.
classSolution {
publicintcountVowelStrings(int n) {
int[] ans =newint[1];
dfs(n, 0, ans);
return ans[0];
}
privatevoiddfs(int rem, int last, int[] ans) {
if (rem == 0) {
ans[0]++;
return;
}
for (int i = last; i < 5; i++) {
dfs(rem - 1, i, ans);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
classSolution {
funcountVowelStrings(n: Int): Int {
var ans = 0fundfs(rem: Int, last: Int) {
if (rem ==0) {
ans++return }
for (i in last until 5) {
dfs(rem - 1, i)
}
}
dfs(n, 0)
return ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
classSolution:
defcountVowelStrings(self, n: int) -> int:
ans: int =0defdfs(rem: int, last: int) ->None:
nonlocal ans
if rem ==0:
ans +=1returnfor i in range(last, 5):
dfs(rem -1, i)
dfs(n, 0)
return ans
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
impl Solution {
pubfncount_vowel_strings(n: i32) -> i32 {
fndfs(rem: i32, last: usize, ans: &muti32) {
if rem ==0 {
*ans +=1;
return;
}
for i in last..5 {
dfs(rem -1, i, ans);
}
}
letmut ans =0;
dfs(n, 0, &mut ans);
ans
}
}
The problem has overlapping subproblems and optimal substructure, making it suitable for dynamic programming. For each position in the string, we can choose any vowel that is not less than the previous one, and we can cache results for subproblems defined by the remaining length and the current vowel index.
classSolution {
publicintcountVowelStrings(int n) {
int[][] dp =newint[n + 1][5];
return dfs(n, 0, dp);
}
privateintdfs(int rem, int last, int[][] dp) {
if (rem == 0) return 1;
if (dp[rem][last]!= 0) return dp[rem][last];
int ans = 0;
for (int i = last; i < 5; i++) {
ans += dfs(rem - 1, i, dp);
}
dp[rem][last]= ans;
return ans;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
classSolution {
funcountVowelStrings(n: Int): Int {
val dp = Array(n + 1) { IntArray(5) }
fundfs(rem: Int, last: Int): Int {
if (rem ==0) return1if (dp[rem][last] !=0) return dp[rem][last]
var ans = 0for (i in last until 5) {
ans += dfs(rem - 1, i)
}
dp[rem][last] = ans
return ans
}
return dfs(n, 0)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
classSolution:
defcountVowelStrings(self, n: int) -> int:
dp: list[list[int]] = [[0] *5for _ in range(n +1)]
defdfs(rem: int, last: int) -> int:
if rem ==0:
return1if dp[rem][last]:
return dp[rem][last]
ans =0for i in range(last, 5):
ans += dfs(rem -1, i)
dp[rem][last] = ans
return ans
return dfs(n, 0)
The key idea is to count the number of lexicographically sorted vowel strings of length n by building up solutions for smaller lengths. For each position, we can only use vowels that are the same or come after the previous vowel. We use a DP table where dp[i][j] represents the number of strings of length i starting with the j-th vowel or any vowel after it.
Initialize a 2D DP table dp of size (n+1) x 5, where dp[i][j] is the number of strings of length i starting with the j-th vowel or later.
For length 1 (i = 1), set dp[1][j] = 1 for all vowels j (since each vowel alone is a valid string).
For lengths from 2 to n, fill dp[i][j] by summing dp[i-1][j] (strings starting with the same vowel) and dp[i][j+1] (strings starting with a later vowel).
The answer is dp[n][0], representing all strings of length n starting with any vowel.
classSolution {
funcountVowelStrings(n: Int): Int {
val dp = Array(n + 1) { IntArray(5) }
for (j in0..4) dp[1][j] = 1for (i in2..n) {
for (j in4 downTo 0) {
dp[i][j] = dp[i - 1][j] + if (j < 4) dp[i][j + 1] else0 }
}
return dp[n][0]
}
}
1
2
3
4
5
6
7
8
9
classSolution:
defcountVowelStrings(self, n: int) -> int:
dp: list[list[int]] = [[0] *5for _ in range(n +1)]
for j in range(5):
dp[1][j] =1for i in range(2, n +1):
for j in range(4, -1, -1):
dp[i][j] = dp[i -1][j] + (dp[i][j +1] if j <4else0)
return dp[n][0]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
impl Solution {
pubfncount_vowel_strings(n: i32) -> i32 {
let n = n asusize;
letmut dp =vec![vec![0; 5]; n +1];
for j in0..5 {
dp[1][j] =1;
}
for i in2..=n {
for j in (0..5).rev() {
dp[i][j] = dp[i -1][j] +if j <4 { dp[i][j +1] } else { 0 };
}
}
dp[n][0]
}
}
A useful pattern here is that adding ‘a’ to every string of length n-1 preserves lexicographic order, and likewise, ’e’ can be added to strings that start with ’e’ or any vowel after it. For example, when n = 3:
n
a
e
i
o
u
1
5
4
3
2
1
2
15
10
6
3
1
3
35
20
10
4
1
For n = 1, there is 1 string starting with ‘u’, 2 with ‘o’ (counting those starting with ‘u’), and so forth. For n = 2, the count for ‘u’ is still 1, while for ‘o’ it is the sum of strings of length 2 starting with ‘u’ and those of length 1 starting with ‘o’, and so on. Here, dp[i][j] gives the number of strings of length i that begin with the j-th vowel or any vowel after it. The DP recurrence is:
The allowed characters are the five vowels ["a","e","i","o","u"].
Lexicographical order means that, once a vowel like e appears at position i, no earlier vowel can appear after any different vowel; for example, strings like eoe, eie, or eae are not valid because after using another vowel, e cannot be used again without breaking the order.
Thus, every valid string is made up of consecutive blocks of the same vowel in order, such as aaiiiiu (which can be described as 2a4i1u). The string is uniquely determined by the lengths of these blocks.
The problem reduces to counting the ways to distribute n positions among the five vowels in order, which is equivalent to placing 4 separators among n slots.
Using the stars and bars method, the number of ways is C(n+4, 4) = (n+1)(n+2)(n+3)(n+4)/24, since the order of blocks is fixed and we divide by 4! to account for indistinguishable separators.