来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum-ii
实现语言:Java
文章记录的是第一次做力扣题时的代码,之后做题的代码放在GitHub上了,由于博客中的文章有点多,挨个修改费时费力,博客中写的有关力扣的文章和GitHub中的代码并不完全对应。力扣题GitHub地址
题目
给定一个数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用一次。
说明:
- 所有数字(包括目标数)都是正整数。
- 解集不能包含重复的组合
示例
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
方法:回溯
以数组 candidates = [2,5,2,1,2], target = 5
为例,访问的节点如下图所示。其中,绿色框表示当前节点的值,红色框表示不再继续向下访问,F 表示当前路径上的所有值的总和大于目标值,T 表示当前路径上的所有值的总和等于目标值。
第一次访问,以数组中第一个节点 2 为起点。其中,列表 [2,1,2]
和 [2,2,1]
重复,不再添加。
![](https://i-blog.csdnimg.cn/blog_migrate/d9f6dfab146f86283c4a5a97b2cbd9e8.png)
第二次访问,以数组中第二个节点 5 为起点。
![](https://i-blog.csdnimg.cn/blog_migrate/fbbdeea07ac81e9a747aff06cb2054ae.png)
第三次访问,以数组中第三个节点 2 为起点。
![](https://i-blog.csdnimg.cn/blog_migrate/55801281239d7b6b39feba634eeec770.png)
第四次访问,以数组中第四个节点 1 为起点。
![](https://i-blog.csdnimg.cn/blog_migrate/2f7f528f8c3261413430f7ef70b53c52.png)
第五次访问,以数组中第五个节点 2 为起点。
![](https://i-blog.csdnimg.cn/blog_migrate/68e419dd5b64a6e1cc30a2c7cfc759f9.png)
代码实现
import java.util.List;
import java.util.LinkedList;
import java.util.Set;
import java.util.HashSet;
import java.util.Comparator;
class Solution {
Set<List<Integer>> set = new HashSet<>(); // 重复的列表不添加
Stack<Integer> stack = new Stack<>();
int sum = 0;
// 比较器
Comparator<Integer> comparator = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
};
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
for (int i=0; i<candidates.length; i++) {
stack.push(i);
sum += candidates[i];
backtracking(candidates, target, i);
sum -= candidates[stack.peek()];
stack.pop();
}
List<List<Integer>> res = new LinkedList<>();
for (List<Integer> tmp : set) {
res.add(tmp);
}
return res;
}
public void backtracking (int[] candidates, int target, int i) {
if (sum > target) return;
if (sum == target) {
List<Integer> tmp = new LinkedList<>();
for (int k: stack)
tmp.add(candidates[k]);
tmp.sort(comparator);
set.add(tmp);
return;
}
// 访问下一层的邻接点
for (int j=i+1; j<candidates.length; j++) {
stack.push(j);
sum += candidates[j];
backtracking(candidates, target, j);
sum -= candidates[stack.peek()];
stack.pop();
}
}
}
执行用时:1293 ms
内存消耗:39.4 MB