1、题目链接
2、题目大意
本题是在组合总和的基础上进行了些许修改,建议大家先看组合总数的题解,以下为题目大意:
给定一个正整数数组 candidates 和一个正整数目标数 target,在数组中选择任意个数字,使其和等于目标数,问这样的选择方法有哪些。其中每个数字在每个组合中,只能选择一次。
题目同样要求组合不能重复。
3、样例输入
candidates = [10,1,2,7,6,1,5], target = 8
candidates = [2,5,2,1,2], target = 5
4、样例输出
[ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ]
[ [1,2,2], [5] ]
5、思路
由于我是先做了组合总和,再做的本题,因此我的方法是在组合总和的方法基础上进行了修改。
本题中给的数组是有重复数字的,且数字只能使用一次,
而在组合总和这个题中的数组是没有重复数字的,且数字使用次数无限,因此作如下转换:
首先通过 map 集合记录所给数组中所有数字的出现次数,而后将 map 的 key 值集合转换为没有重复数字的数组,那么就可以直接使用组合总和中的递归函数来进行运算,只需在剪枝的时候,判断当前数字的使用次数是否已经用完即可。
6、代码
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ans = new ArrayList<>();
Map<Integer, Integer> map = new TreeMap<>();
for (int candidate : candidates) {
map.put(candidate, map.get(candidate) == null ? 1 : map.get(candidate) + 1);
}
//System.out.println(map);
int[] candidates2 = new int[map.size()];
int i = 0;
for (int num : map.keySet()) {
candidates2[i++] = num;
}
dfs(map, candidates2, target, 0, new ArrayList<>(), ans);
return ans;
}
private void dfs(Map<Integer, Integer> map, int[] candidates, int target, int index, List<Integer> list, List<List<Integer>> ans) {
if (target == 0) {
ans.add(list);
return;
}
for (int i = index; i < candidates.length; i++) {
if (map.get(candidates[i]) > 0 && target >= candidates[i]) {
map.put(candidates[i], map.get(candidates[i]) - 1);
list.add(candidates[i]);
dfs(map, candidates, target - candidates[i], i, new ArrayList<>(list), ans);
list.remove(list.size() - 1);
map.put(candidates[i], map.get(candidates[i]) + 1);
}
}
}
}
7、注意事项
本题代码的注意事项与组合总和的注意事项一致。