给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:根据示例 1:输入: candidates = [2,3,6,7],target = 7。
上面的思路就可以画成下面的树形图。
其实这里思路已经介绍完了,大家可以自己尝试在纸上画一下这棵树。然后编码实现,如果遇到问题,再看下面的文字。
说明:
把文字的部分去掉。
如果这样编码的话,会发现提交不能通过,这是因为递归树画的有问题,下面看一下是什么原因。
画出图以后,我看了一下,我这张图画出的结果有 4 个 0,对应的路径是 [[2, 2, 3], [2, 3, 2], [3, 2, 2], [7]],而示例中的解集只有 [[7], [2, 2, 3]],很显然,重复的原因是在较深层的结点值考虑了之前考虑过的元素,因此我们需要设置“下一轮搜索的起点”即可(这里可能没有说清楚,已经尽力了)。
去重复
剪枝提速
如果一个数位搜索起点都不能搜索到结果,那么比它还大的数肯定搜索不到结果,基于这个想法,我们可以对输入数组进行排序,以减少搜索的分支;
排序是为了提高搜索速度,非必要;
搜索问题一般复杂度较高,能剪枝就尽量需要剪枝。把候选数组排个序,遇到一个较大的数,如果以这个数为起点都搜索不到结果,后面的数就更搜索不到结果了。
参考代码:
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
int len = candidates.length;
// 排序是为了提前终止搜索
Arrays.sort(candidates);
dfs(candidates, len, target, 0, new ArrayDeque<>(), res);
return res;
}
/**
* @param candidates 数组输入
* @param len 输入数组的长度,冗余变量
* @param residue 剩余数值
* @param begin 本轮搜索的起点下标
* @param path 从根结点到任意结点的路径
* @param res 结果集变量
*/
private void dfs(int[] candidates,
int len,
int residue,
int begin,
Deque<Integer> path,
List<List<Integer>> res) {
if (residue == 0) {
// 由于 path 全局只使用一份,到叶子结点的时候需要做一个拷贝
res.add(new ArrayList<>(path));
return;
}
for (int i = begin; i < len; i++) {
// 在数组有序的前提下,剪枝
if (residue - candidates[i] < 0) {
break;
}
path.addLast(candidates[i]);
dfs(candidates, len, residue - candidates[i], i, path, res);
path.removeLast();
}
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。