LeetCode解题 40:Combination Sum II
Problem 40: Combination Sum II [Medium]
Given a collection of candidate numbers (candidates
) and a target number (target
), find all unique combinations in candidates
where the candidate numbers sums to target
.
Each number in candidates
may only be used once in the combination.
Note:
- All numbers (including
target
) will be positive integers. - The solution set must not contain duplicate combinations.
Example 1:
Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
Example 2:
Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
[1,2,2],
[5]
]
来源:LeetCode
解题思路
与39题类似。
基本思路为回溯算法,采用深度优先,并使用剪枝减少无用搜索。
- 首先将候选数组按升序排序。
- 每一轮循环从候选数组中选择一个数x加入组合,比较
target'
与x的大小,此处target'
代表每一轮中新的目标值,根据比较结果分为三种情况:
a. 如果target' - x = 0
,说明组合中sum = target,将该种组合加入最终结果result列表里,并剪枝。
b. 如果target' - x < 0
,说明组合中sum > target,不能再加入任何数,也不能将x替换为更大的候选数,因此这里直接剪枝。
c. 如果target' - x > 0
,说明组合中sum < target,还可以继续深入搜索,更新target' = target' - x
,进行递归搜索。 - 注意1:题目中说每个数只能用一次,因此每次深度搜索时要从下一个坐标(index + 1)开始搜索。
- 注意2:为了防止重复组合,在
backtracking()
中的循环内,即广度搜索时,如果下一个数在candidates
数组中是重复的,则需要跳过搜索。
要点:回溯算法
、剪枝
Solution (Java)
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
Arrays.sort(candidates);
int N = candidates.length;
if(N == 0) return result;
List<Integer> comb = new ArrayList<Integer>();
backtracking(candidates, 0, N, target, comb, result);
return result;
}
private void backtracking(int [] candidates, int index, int N, int target, List<Integer> comb, List<List<Integer>> result){
int temp = 0;
for(int i = index; i < N; i++){
// skip duplicate candidates
while(i < N && candidates[i] == temp) i++;
if(i == N) return;
temp = candidates[i];
int next_target = target - candidates[i];
if(next_target == 0){
comb.add(candidates[i]);
result.add(comb);
return;
}
else if(next_target < 0){
return;
}
else{
List<Integer> next_comb = new ArrayList<Integer>(comb);
next_comb.add(candidates[i]);
// search i+1 ~ N-1, candidates[i] may only be used once
backtracking(candidates, i+1, N, next_target, next_comb, result);
}
}
}
}
修改过程
- 没有在广度搜索时跳过
candidates
中重复的数字,导致输入[10,1,2,7,6,1,5]
,8
,输出的集合为:[[1,1,6],[1,2,5],[1,7],[1,2,5],[1,7],[2,6]]
,其中[1,2,5]和[1,7]都输出了两遍,是因为candidates
中有两个1,没有跳过。