问题:从一个int数组array中选出m个数。
限制:1. array中元素互不相同;2. m不大于array的长度n。
思路:C(n,m) = C(n-1,m) + C(n-1,m-1)。考虑元素array[0]和子数列array[1..n-1],如果array[0]出现在结果中,那么就从array[1..n-1]中选出m-1个,否则从array[1..n-1]中选出m个。
代码:一种组合对应一个HashSet<Integer>,所有组合的集合构成一个HashSet<HashSet<Integer>>。
1
public static HashSet<HashSet<Integer>> combination(int array[], int m){
2
if(array == null || m > array.length) return null;
3
return combination(array, m, 0);
4
}
5
6
private static HashSet<HashSet<Integer>> combination(int array[], int m, int start){
7
HashSet<HashSet<Integer>> result_set = null;
8
HashSet<Integer> hs = null;
9
10
// C(n,0)
11
if(m == 0){
12
result_set = new HashSet<HashSet<Integer>>();
13
result_set.add(new HashSet<Integer>());
14
return result_set;
15
}
16
17
// C(n,1)
18
if(m == 1) {
19
result_set = new HashSet<HashSet<Integer>>();
20
for(int i=start; i!=array.length; ++i) {
21
hs = new HashSet<Integer>();
22
hs.add(array[i]);
23
result_set.add(hs);
24
}
25
return result_set;
26
}
27
28
// C(n,n)
29
if(m == array.length - start) {
30
result_set = new HashSet<HashSet<Integer>>();
31
hs = new HashSet<Integer>();
32
for(int i=start; i!=array.length; ++i)
33
hs.add(array[i]);
34
result_set.add(hs);
35
return result_set;
36
}
37
38
// C(n,m) = C(n-1,m) + C(n-1,m-1)
39
HashSet<HashSet<Integer>> set1 = combination(array, m-1, start+1);
40
HashSet<HashSet<Integer>> set2 = combination(array, m, start+1);
41
for(HashSet<Integer> s : set1) s.add(array[start]);
42
for(HashSet<Integer> s : set2) set1.add(s);
43
44
return set1;
45
}
public static HashSet<HashSet<Integer>> combination(int array[], int m){2
if(array == null || m > array.length) return null;3
return combination(array, m, 0);4
}5
6
private static HashSet<HashSet<Integer>> combination(int array[], int m, int start){7
HashSet<HashSet<Integer>> result_set = null;8
HashSet<Integer> hs = null;9
10
// C(n,0)11
if(m == 0){12
result_set = new HashSet<HashSet<Integer>>();13
result_set.add(new HashSet<Integer>());14
return result_set;15
}16
17
// C(n,1)18
if(m == 1) {19
result_set = new HashSet<HashSet<Integer>>();20
for(int i=start; i!=array.length; ++i) {21
hs = new HashSet<Integer>();22
hs.add(array[i]);23
result_set.add(hs);24
}25
return result_set;26
}27
28
// C(n,n)29
if(m == array.length - start) {30
result_set = new HashSet<HashSet<Integer>>();31
hs = new HashSet<Integer>();32
for(int i=start; i!=array.length; ++i)33
hs.add(array[i]);34
result_set.add(hs);35
return result_set;36
}37
38
// C(n,m) = C(n-1,m) + C(n-1,m-1)39
HashSet<HashSet<Integer>> set1 = combination(array, m-1, start+1);40
HashSet<HashSet<Integer>> set2 = combination(array, m, start+1);41
for(HashSet<Integer> s : set1) s.add(array[start]);42
for(HashSet<Integer> s : set2) set1.add(s);43
44
return set1;45
}讨论:
1. 元素互异的限制可放宽,把HashSet换成别的,例如ArrayList。
2. int型的限制可放宽,搞个泛型吧,很cool。
3. 时间复杂度怎么算?一眼看不出来,改天再深究。
4. 对返回void且在方法体内调用println的做法比较反感,情愿用集合之集合来存储结果。
5. 对非递归算法无爱并敬而远之,始终认为那是牛们为了戏虐猪羊而写的。



浙公网安备 33010602011771号