数字组合问题:Combination,CombinationSum,CombinationSum2,CombinationSum3

Combination问题描述:给定n和k,找出1-n之间所有k个数的组合,例如:n=3,k=2,返回

[[1,2]  [1,3]  [2,3]]

算法分析:利用递归。递归边界就是curr.size()==k。

 1 public List<List<Integer>> combine(int n, int k)
 2     {
 3         List<List<Integer>> result = new ArrayList<>();
 4         List<Integer> current = new ArrayList<>();
 5         if(n <= 0 || n<k)
 6         {
 7             return result;
 8         }
 9         combine(n, k, 1, current, result);
10         return result;
11     }
12     //递归和n,k无关,只是边界条件和k相关,n,k在递归中不变化。
13     public void combine(int n, int k, int start, List<Integer> current, List<List<Integer>> result)
14     {
15         if(current.size() == k)
16         {
17             List<Integer> temp = new ArrayList<>(current);
18             result.add(temp);
19             return ;
20         }
21         for(int i = start; i <= n; i ++)
22         {
23             current.add(i);
24             combine(n, k, i+1, current, result);
25             current.remove(current.size()-1);
26         }
27     }

CombinationSum问题描述:给一组数字和target,这组数字没有重复元素,找出这组数字中相加为target的集合。

例如给定set[2,3,6,7]和target=7.返回[[7]  [2,2,3]]. 也就是说,数字集合没有重复,但是结果集里面可以重复某个元素。先把数据集排序。

算法分析:利用递归,边界条件是target==0.

 1 public List<List<Integer>> combinationSum(int[] candidates, int target) 
 2     {
 3         List<List<Integer>> result = new ArrayList<>();
 4         List<Integer> current = new ArrayList<>();
 5         if(candidates == null || candidates.length == 0)
 6         {
 7             return result;
 8         }
 9         Arrays.sort(candidates);
10         combinationSum(candidates, target, 0, current, result);
11         return result;
12     }
13     
14     public void  combinationSum(int[] candidates, int target, int i, List<Integer> curr, List<List<Integer>> result)
15     {
16         if(target == 0)//组合成功
17         {
18             List<Integer> temp = new ArrayList<>(curr);
19             result.add(temp);
20             return;
21         }
22         for(int j = i; j < candidates.length; j ++)
23         {
24             if(target < candidates[j])
25             {
26                 return ;
27             }
28             curr.add(candidates[j]);
29             combinationSum(candidates, target-candidates[j], j, curr, result);
30             //如果上一步递归返回则去掉最后加入的元素,然后回溯。
31             //curr.remove(candidates[j]);错误,list的参数是index
32             curr.remove(curr.size()-1);
33         }
34     }

CombinationSum2问题描述:给定数据集里面有重复元素,但是结果集中每个数据集中的元素只能出现一次。

例如:[10, 1, 2, 7, 6, 1, 5],target=8,返回 17  125 26 116

算法分析:递归的下标要取j+1,然后还要过滤相同序列。使用hashset。

 1 public List<List<Integer>> combinationSum2(int[] candidates, int target) {
 2         List<List<Integer>> result = new ArrayList<>();
 3         List<Integer> current = new ArrayList<>();
 4         if(candidates == null || candidates.length == 0)
 5         {
 6             return result;
 7         }
 8         Arrays.sort(candidates);
 9         combinationSum2(candidates, target, 0, current, result);
10         //利用hashset过滤重复元素
11         HashSet<List<Integer>> set = new HashSet<>(result);
12         result.clear();
13         result.addAll(set);
14         return result;
15     }
16     
17     public void combinationSum2(int[] candidates, int target, int i, List<Integer> curr, List<List<Integer>> result)
18     {
19         if(target == 0)
20         {
21             List<Integer> temp = new ArrayList<>(curr);
22             result.add(temp);
23             return;
24         }
25         for(int j = i; j < candidates.length; j ++)
26         {
27             if(candidates[j] > target)
28             {
29                 return;
30             }
31             curr.add(candidates[j]);
32             //下标j+1,过滤相同元素
33             combinationSum2(candidates, target-candidates[j], j + 1, curr, result);
34             curr.remove(curr.size()-1);
35         }
36     }

CombinationSum3:给定k和target,找到1-9集合中满足k个数的和=target的序列集合。

例如:k=3,target=6.返回123 , k=3, target=9,返回126,135,234

算法分析:这道题和3Sum很像,因为3Sum不能用递归,因为时间复杂度太高。还有一类问题,就是说i<j<k, 返回i,j,k,,满足i+j+k=target

这种只能用三层for循环了,因为没有数据集的限制。

 1 public List<List<Integer>> combinationSum3(int k, int n) {
 2         List<List<Integer>> result = new ArrayList<>();
 3         List<Integer> curr = new ArrayList<>();
 4         combinationSum3(k, n, 1, curr, result);
 5         return result;
 6     }
 7     
 8     public void combinationSum3(int k, int target, int i, List<Integer> curr, List<List<Integer>> result)
 9     {
10         if(curr.size() == k && target == 0)
11         {
12             result.add(new ArrayList<Integer>(curr));
13             return;
14         }
15         
16         for(int j = i; j <= 9; j ++)
17         {
18             if(target < j)
19             {
20                 return ;
21             }
22             curr.add(j);
23             combinationSum3(k, target - j, j+1, curr, result);
24             curr.remove(curr.size() - 1);
25         }
26     }
原文地址:https://www.cnblogs.com/masterlibin/p/5600474.html