40. 组合总和 II
难度 中等
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意: 解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
提示:
1 <= candidates.length <= 1001 <= candidates[i] <= 501 <= target <= 30
题解
这道题也是一道组合的题目,是要查找所有能组成target的组合,且不能重复,这样要求我们遇到相同的数字的时候要特殊处理一下。
例如给出的数据[1,2,2],第二第三个元素重复了,当我们枚举了一、二元素(即[1,2]),然后枚举一、三元素时(即[1,2]),这就有相同组合了。
再举个例子[1,2,2,2],当我们枚举了一、二、三元素(即[1,2,2]),然后枚举一、三、四元素时(即[1,2,2]),又出现相同组合了。
通过上面两个例子知道,当我们前面出现一个相同的元素(例如2),我们没有选择前面这个元素,此时选择当前位置的元素(2),就会出现重复的子集。因为如果选择了前一个元素;和另一种不选择前一个元素,选择当前元素;都是同样的排列。所以我们要处理这种情况,只取第一个相同的元素。
核心代码
if(i > begin && candidates[i - 1] == candidates[i]){//遇到相同的元素,直接跳过
continue;
}
AC代码
class Solution {
List<List<Integer>> ans = new ArrayList<List<Integer>>();//结果集
List<Integer> list = new ArrayList<Integer>();//辅助链表
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);//排序,将相同的元素排列在一起
dfs(candidates, target, 0, 0);
return ans;
}
void dfs(int[] candidates, int target, int begin, int sum){
if(sum == target){//选择元素加权等于terget,找到满足条件的组合
ans.add(new ArrayList<Integer>(list));
return;
}
for(int i = begin; i < candidates.length; i++){//从begin开始枚举
if(i > begin && candidates[i - 1] == candidates[i]){//如果出现相同元素,不枚举
continue;
}
int rs = sum + candidates[i];//加上当前枚举元素
if(rs <= target){//判断枚举之后是否小于target
list.add(candidates[i]);//加入链表
dfs(candidates, target, i + 1, rs);//继续枚举i + 1元素
list.remove(list.size() - 1);//删除链表
}else{
break;
}
}
}
}