1、题目
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2、思路
昨天的组合PLUS升级版啊!!!还是DFS,新增两个不同之处:数字只能使用一次/数组的数字可能重复。
首先,数组先排序以便优化时间;然后当和为target时,组合添加到list里,并把组合最后一个数删除,结束此次递归,return后把此时组合最后一个元素删除并用变量flag记录,在下一次for循环时,如果flag的值和此时数组当前值相同就跳过。(不然就出现相同的组合,如[1,2,3,4]、[1,2,3,4])
测试数据没想好,导致WA一次,第二组自己想的,第一组是题目的,我没通过;[1,1] 2; [1,2,2,2,3,3,4] 10
class Solution {
private List<List<Integer>> list = new ArrayList<List<Integer>>();
private List<Integer> tem;
private int flag;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
tem = new ArrayList<Integer>();
Arrays.sort(candidates);
flag = 0;
dfs(0,target,0,candidates);
return list;
}
public void dfs(int sum, int target,int inx,int[] candidates) {
for (int i = inx; i < candidates.length; i++) {
if(i > 0) {
while(i<candidates.length && flag == candidates[i]) {
if(candidates[i] != candidates[i-1]) {
flag = 0;
break;
}
i++;
}
}
//WA是因为忘记数组越界的问题了,数据[1,1] 2
if(i >= candidates.length) {
return;
}
if(sum+candidates[i] > target) {
return;
}
tem.add(candidates[i]);
if(sum+candidates[i] == target) {
ArrayList<Integer> tem0 = new ArrayList<Integer>();
tem0.addAll(tem);
list.add(tem0);
tem.remove(tem.size()-1);
return;
}
dfs(sum+candidates[i],target,i+1,candidates);
if(tem.size() > 0) {
flag = tem.get(tem.size()-1);
tem.remove(tem.size()-1);
}
}
}
}