LeetCode: combinations

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

解决这个问题有两种思路:

1. 从n个找出k个的所有组合,可以是从n-1个中找到k个的所有组合加上n-1个中找到k-1个的所有组合再加上n

f(n,k) = {f(n-1, k), [f(n-1, k-1), k] }

2. 从n个中找出k个的所有组合,可以是从n个中找到以n结尾的k个的组合,加上从n-1个中找到以n-1结尾的k个的组合,加上。。。。

f(n,k) = { f(n-1, k), f(n-2, k), ...., f(k, k) }

第一种方法可以用递归与dp两种方法。

 1 public static ArrayList<ArrayList<Integer>> combine(int n, int k) {
 2         ArrayList<ArrayList<Integer>>[][] arrayList = new ArrayList[n][k];
 3     
 4         arrayList[0][0] = new ArrayList<ArrayList<Integer>>();
 5         ArrayList<Integer> o = new ArrayList<Integer>();
 6         o.add(1);
 7         arrayList[0][0].add(o);
 8 
 9         for (int i=1; i<n; i++) {
10             for (int j=0; j<=i && j<k; j++) {
11                 if (i!=j){
12                     arrayList[i][j] = new ArrayList<ArrayList<Integer>>(arrayList[i-1][j]);
13                 }
14                 else {
15                     arrayList[i][j] = new ArrayList<ArrayList<Integer>>();
16                 }
17                 
18                 if(j>0) {
19                     ArrayList<ArrayList<Integer>> tmp = new ArrayList<ArrayList<Integer>>();
20                     for (ArrayList<Integer> s : arrayList[i-1][j-1]) {
21                         ArrayList<Integer> t = new ArrayList<Integer>(s);
22                         t.add(i+1);
23                         tmp.add(t);
24                     }
25                     arrayList[i][j].addAll(tmp);
26                 }
27                 else {                
28                     ArrayList<Integer> w = new ArrayList<Integer>();
29                     w.add(i+1);
30                     arrayList[i][j].add(w);
31                 }                
32             }
33         }
34         
35         return arrayList[n-1][k-1];
36     }

其中非常需要注意的是第20行,需要new一个t出来并复制s。如果直接在s上操作会影响之前的结果。

 1 public static ArrayList<ArrayList<Integer>> combine2(int n, int k) {
 2         ArrayList<ArrayList<Integer>> arrayList = new ArrayList<ArrayList<Integer>>();
 3         if ( k==1 ) {
 4             for (int i=1; i<=n; i++) {
 5                 ArrayList<Integer> o = new ArrayList<Integer>();
 6                 o.add(i);
 7                 arrayList.add(o);
 8             }
 9             
10         }
11         else {
12             if ( n > k) {
13                 ArrayList<ArrayList<Integer>> tmp = combine2(n-1, k);
14                 arrayList.addAll(tmp);
15             }
16             for(ArrayList<Integer> s : combine2(n-1, k-1)) {
17                 s.add(n);
18                 arrayList.add(s);
19             }    
20         }
21         
22         return arrayList;
23     }

其中需要注意的是递归的终止条件。当k等于1的时候,是递归的终止条件。另外,在第12行需要判断n和k的关系,否则n<k是会一直递归下去,n可能为负数。

 1 public static ArrayList<ArrayList<Integer>> combine3(int n, int k) {
 2         if(n<k) return null;
 3         ArrayList<ArrayList<Integer>> all = new  ArrayList<ArrayList<Integer>>();       
 4         if(k==1){
 5             for(int i=1;i<=n;i++){
 6                 ArrayList<Integer> al = new ArrayList<Integer>();
 7                 al.add(i);
 8                 all.add(al);
 9             }
10             return all;
11         }
12         for(int i=n;i>=k;i--){                
13             for(ArrayList<Integer> al : combine3(i-1,k-1)){
14                 al.add(i);
15                 all.add(al);
16             }
17         }
18         return all;  
19     }

 


 

我又学会一种方法。。。DFS。比如4个里取3个,第一个数可以取1,2,3,4. 如果第一个数取1,那么第二个数可以取2,然后第三个取3。满足条件,返回这个结果,然后回溯到2那一步,不取3,改取4.[1,2,4]满足条件返回结果。。。。。。

需要注意两个地方。一个是第9行,一定要add new。因为如果直接add的话,因为ArrayList是对象,所以以后对tmp操作会直接影响result中的结果。

第二个是第16行,要删除掉最后添加的元素。当运行到第16行时,tmp为add当前循环里的i的那个状态,因为是从上一个combine回溯回来的。这个时候删除掉最后添加的这个元素,改为增加下一个元素的情况。。比如说tmp = [1, 2],删掉2,改为tmp=[1, 3]...

 1 public static ArrayList<ArrayList<Integer>> combine4(int n, int k) {
 2         ArrayList<Integer> tmp = new ArrayList<Integer>();
 3         ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
 4         combine4(1, n, k, tmp, result);
 5         return result;
 6     }
 7     public static void combine4(int s, int n, int k, ArrayList<Integer> tmp, ArrayList<ArrayList<Integer>> result) {
 8         if (tmp.size() == k) {
 9             result.add(new ArrayList<Integer>(tmp));
10             return;
11         }
12         else {
13             for (int i=s; i<=n; i++) {
14                 tmp.add(i);
15                 combine4(i+1, n, k, tmp, result);
16                 tmp.remove(tmp.size()-1);
17             }
18         }
19     }

 

 

 

 

posted on 2013-11-30 07:36  longhorn  阅读(177)  评论(0编辑  收藏  举报

导航