Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
Note:
- All numbers (including target) will be positive integers.
- Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
- The solution set must not contain duplicate combinations.
For example, given candidate set 2,3,6,7
and target 7
,
A solution set is:
[7]
[2, 2, 3]
Combination Sum II
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
- All numbers (including target) will be positive integers.
- Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
- The solution set must not contain duplicate combinations.
For example, given candidate set 10,1,2,7,6,1,5
and target 8
,
A solution set is:
[1, 7]
[1, 2, 5]
[2, 6]
[1, 1, 6]
解题思路:
这道题是一道典型的搜索算法计算题,其中LeetCode 39为支持重复的求和计算,而LeetCode 40为不支持重复求和的计算题。这两道题的关键都在于深度检索的时候的边界的设定,递归边界为如果结果大于target则相关路径不用继续遍历。LeetCode 40与LeetCode 39的不同在于不支持重复元素,因此,递归函数对应参数level为+1.另外,对于单变量的情况要单独考虑。
代码如下:
Combination Sum:
public class Solution {
List<List<Integer>> result;
List<Integer> solu;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
result = new ArrayList<>();
solu = new ArrayList<>();
Arrays.sort(candidates);
getCombination(candidates, target, 0, 0);
return result;
}
public void getCombination(int[] candidates, int target, int sum, int level){
if(sum>target) return;
if(sum==target){
result.add(new ArrayList<>(solu));
return;
}
for(int i=level;i<candidates.length;i++){
sum+=candidates[i];
solu.add(candidates[i]);
getCombination(candidates, target, sum, i);
solu.remove(solu.size()-1);
sum-=candidates[i];
}
}
}
Combination Sum II:
public class Solution {
List<List<Integer>> result;
List<Integer> solu;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
result = new ArrayList<>();
solu = new ArrayList<>();
Arrays.sort(candidates);
getCombination(candidates, target, 0, 0);
return result;
}
public void getCombination(int[] candidates, int target, int sum, int level){
if(sum>target) return;
if(sum==target){
if(!result.contains(new ArrayList<>(solu)))
result.add(new ArrayList<>(solu));
return;
}
if(candidates.length==1){//添加的条件
if(target==candidates[0]){
solu.add(candidates[0]);
result.add(solu);
}
return ;
}
for(int i=level;i<candidates.length;i++){
sum+=candidates[i];//
solu.add(candidates[i]);
getCombination(candidates, target, sum, i+1);//新的递归参数
solu.remove(solu.size()-1);
sum-=candidates[i];
}
}
}
实际上,该算法可以优化处理,对剪枝进行优化,我们在判断出当前节点符合或者大于target的时候,对同一个层次之后的节点便不再需要遍历,修改之后的代码如下:
public int getCombination(int[] candidates, int target, int sum, int level){
if(sum>target) return 1;//剪枝
if(sum==target){
if(!result.contains(new ArrayList<>(solu)))
result.add(new ArrayList<>(solu));
return 1;//剪枝
}
if(candidates.length==1){
if(target==candidates[0]){
solu.add(candidates[0]);
result.add(solu);
}
return 0;
}
for(int i=level;i<candidates.length;i++){
sum+=candidates[i];//
solu.add(candidates[i]);
int j=getCombination(candidates, target, sum, i+1);
solu.remove(solu.size()-1);
sum-=candidates[i];
if(j==1){//剪枝
i=candidates.length;
}
}
return 0;
}