给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
1 2 3 4 5 6 7 8
| 输入: candidates = [10,1,2,7,6,1,5], target = 8, 所求解集为: [ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ]
|
示例 2:
1 2 3 4 5 6
| 输入: candidates = [2,5,2,1,2], target = 5, 所求解集为: [ [1,2,2], [5] ]
|
来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
本题和39. 组合总和类似,但是多出了限制条件,要求排列组合不能重复。我们先用最原始的思路在39. 组合总和上进行改造,为了避免重复,我们可以效仿47. 全排列 II的样子,创建一个used数组,用来标记当前元素是否已经被使用,接着,我们在每次backtrack的时候判断result里面是否有当前满足条件的track如果有的话就直接跳过,最后就是常规的回溯算法的标准框架。
具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { List<List<Integer>> result = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) { LinkedList<Integer> track = new LinkedList<>(); boolean[] used = new boolean[candidates.length]; Arrays.sort(candidates); backtrack(candidates, target, 0, track, used); return result; }
void backtrack(int[] candidates, int target, int start, LinkedList<Integer> track, boolean[] used) { if (target == 0) { if (result.contains(track)) return; result.add(new LinkedList<>(track)); return; } if (target < 0) { return; }
for (int i = start; i < candidates.length; i++) { if (used[i]) { continue; } track.add(candidates[i]); used[i] = true; backtrack(candidates, target - candidates[i], i, track, used); used[i] = false; track.removeLast(); } } }
|

这个结果说实话,是没有办法让人满意的,我们来思考一下如何优化。如果排序后,candidates中相邻两个元素相等,其实排列的结果是重复的,我们可以直接跳过。而且,还有一种更好的办法替代used数组,就是让每次backtrack传进去的start + 1。
具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Solution { List<List<Integer>> result = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) { LinkedList<Integer> track = new LinkedList<>(); Arrays.sort(candidates); backtrack(candidates, target, 0, track); return result; }
void backtrack(int[] candidates, int target, int start, LinkedList<Integer> track) { if (target == 0) { result.add(new LinkedList<>(track)); return; } if (target < 0) { return; }
for (int i = start; i < candidates.length; i++) { if (i > start && candidates[i] == candidates[i - 1]) { continue; } track.add(candidates[i]); backtrack(candidates, target - candidates[i], i + 1, track);
track.removeLast(); } } }
|
