这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
前言
力扣第四十题 组合总和 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]
]
一、思路
这一题和前文的力扣第三十九题-组合总和基本是差不多的,就有一点不同:candidates 中的每个数字在每个组合中只能使用一次。
这一题总体的思路还是通过递归来实现的,但是为了防止组合中的值重复,我们要做三件事情:
- 将
candidates数组排序 - 下一次递归的下标为
i + 1 - 递归前要防止同级节点的相同值入栈
举个例子
此处以示例1中的 candidates = [10,1,2,7,6,1,5], target = 8 作为例子
- 先将数组排序,
candidates = [1, 1, 2, 5, 6, 7, 10] - 选取第一个元素
1,此时1 < 8,元素1入栈 - 递归1:选取第二个元素
1,此时(1 + 1) < 8,元素1入栈 - 递归2:选取第三个元素
2,此时(1 + 1 + 2) < 8,元素2入栈 - 递归3:选取第四个元素
5,此时(1 + 1 + 2 + 5) > 8。说明无法找到正确的解,结束此层递归。 - 递归2:元素
2出栈,选取第四个元素5,此时(1 + 1 + 5) < 8,元素5入栈 - 递归3:选取第五个元素
6,此时(1 + 1 + 5 + 6) > 8。说明无法找到正确的解,结束此层递归。 - 递归2:元素
5出栈,选取第五个元素6,此时(1 + 1 + 6) == 8。找到了一组正确的解[1, 1, 6] - ......,后面的解也是通过相同的方式得到的
- 最终可以得到正确的解为:
[1, 1, 6], [1, 2, 5], [1, 7], [2, 6]
二、实现
实现代码
实现方式与思路中保持一致
/**
* 回溯算法(值不可以重复)
*/
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ret = new ArrayList<>();
int len = candidates.length;
if (len == 0)
return ret;
Stack<Integer> path = new Stack<>();
// 回溯前先将数组排序
Arrays.sort(candidates);
dfs(candidates, 0, target, path, ret);
return ret;
}
/**
* 回溯的实现
* @param candidates 候选数组
* @param begin 开始搜索位置
* @param target 目标值
* @param path 路径
* @param ret 结果集
*/
private void dfs(int[] candidates, int begin, int target, Stack<Integer> path, List<List<Integer>> ret) {
// target为负值和0时不分支
if (target < 0)
return;
if (target == 0) {
ret.add(new ArrayList<>(path));
return;
}
// 从begin开始搜索
int len = candidates.length;
for (int i=begin; i<len; i++) {
// 同级节点不能重复
if (i > begin && candidates[i] == candidates[i-1])
continue;
// 路径进栈
path.push(candidates[i]);
// 考虑到剪枝,下次搜索起点为i+1
dfs(candidates, i+1, target - candidates[i], path, ret);
// 路径出栈
path.pop();
}
}
测试代码
public static void main(String[] args) {
int[] nums = {10,1,2,7,6,1,5};
new Number40().combinationSum2(nums, 8);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥