|
|
|
|
package class39;
|
|
|
|
|
|
|
|
|
|
// 来自百度
|
|
|
|
|
// 给定一个字符串str,和一个正数k
|
|
|
|
|
// str子序列的字符种数必须是k种,返回有多少子序列满足这个条件
|
|
|
|
|
// 已知str中都是小写字母
|
|
|
|
|
// 原始是取mod
|
|
|
|
|
// 本节在尝试上,最难的
|
|
|
|
|
// 搞出桶来,组合公式
|
|
|
|
|
public class Code03_SequenceKDifferentKinds {
|
|
|
|
|
|
|
|
|
|
// bu -> {6,7,0,0,6,3}
|
|
|
|
|
// 0 1 2 3 4 5
|
|
|
|
|
// a b c d e f
|
|
|
|
|
// 在桶数组bu[index....] 一定要凑出rest种来!请问几种方法!
|
|
|
|
|
public static int f(int[] bu, int index, int rest) {
|
|
|
|
|
if (index == bu.length) {
|
|
|
|
|
return rest == 0 ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
// 最后形成的子序列,一个index代表的字符也没有!
|
|
|
|
|
int p1 = f(bu, index + 1, rest);
|
|
|
|
|
// 最后形成的子序列,一定要包含index代表的字符,几个呢?(所有可能性都要算上!)
|
|
|
|
|
int p2 = 0;
|
|
|
|
|
if (rest > 0) { // 剩余的种数,没耗尽,可以包含当前桶的字符
|
|
|
|
|
p2 = (1 << bu[index] - 1) * f(bu, index + 1, rest - 1);
|
|
|
|
|
}
|
|
|
|
|
return p1 + p2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int nums(String s, int k) {
|
|
|
|
|
char[] str = s.toCharArray();
|
|
|
|
|
int[] counts = new int[26];
|
|
|
|
|
for (char c : str) {
|
|
|
|
|
counts[c - 97]++;
|
|
|
|
|
}
|
|
|
|
|
return ways(counts, 0, k);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int ways(int[] c, int i, int r) {
|
|
|
|
|
if (r == 0) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (i == c.length) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// math(n) -> 2 ^ n -1
|
|
|
|
|
return math(c[i]) * ways(c, i + 1, r - 1) + ways(c, i + 1, r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// n个不同的球
|
|
|
|
|
// 挑出1个的方法数 + 挑出2个的方法数 + ... + 挑出n个的方法数为:
|
|
|
|
|
// C(n,1) + C(n,2) + ... + C(n,n) == (2 ^ n) -1
|
|
|
|
|
public static int math(int n) {
|
|
|
|
|
return (1 << n) - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
String str = "acbbca";
|
|
|
|
|
int k = 3;
|
|
|
|
|
System.out.println(nums(str, k));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|