回溯——39. 组合总和
前几题回溯,都是能明确知道回溯树的depth,因此终止条件是:
1 if (path.size() == k) { 2 if (符合题目要求) { 3 result.add((ArrayList) path.clone()); 4 } 5 }
这一题的要求只是:
- 和为target
- 唯一组合
- 数据可重复
因此最简单的想法如下:
1 private void backtracking(int[] candidates, int target, int startIndex, int sum) { 2 if (sum == target) { 3 result.add((ArrayList) path.clone()); 4 } 5 6 //每次回溯的起点都是当前元素 7 for (int i = startIndex; i < candidates.length; ++i) { 8 path.add(candidates[i]); 9 //更新阶段总和sum 10 backtracking(candidates, target, i, sum+candidates[i]); 11 path.remove(path.size() - 1); 12 } 13 }
但是跑样例就已经报栈溢出的错误。因此寻求剪枝。
将原数组先排序,使用
Arrays.sort() 时间开销仅为nlogn,这样数组就是非降序数组。在遍历回溯树的过程中,对于下一个数的选择,可以判断其值+当前总和sum是否<=target,若不符合则不可能总和最后==target(数组中所有元素为正整数)private void backtracking(int[] candidates, int target, int startIndex, int sum) { if (sum == target) { result.add((ArrayList) path.clone()); } //path中的下一个元素必须 <= target - sum,否则在有序正整数数组中将不可能达成sum == target for (int i = startIndex; i < candidates.length && candidates[i] <= target - sum; ++i) { path.add(candidates[i]); backtracking(candidates, target, i, sum+candidates[i]); path.remove(path.size() - 1); } }