组合总和
难度:中等
为了加深对dfs的理解,又找了题来练练手。
同样的思路,运用dfs求解的核心在于两点:
1、找到截止条件
2、找出“候选人”并筛选
这道题的截止条件为数组中的数字总和大于target,而候选人则为candidates数组中的任意元素,因为题干中提到元素可以多次使用,则无筛选条件
代码如下:
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
dfs(candidates,target,res,integers,0);
return res;
}
/**
* @param candidates 候选数组
* @param target 每减去一个元素,目标值变小
* @param res 结果集列表
* @param integers 当前数组
* @param sum 当前数组元素总和
*/
public void dfs(int[] candidates,int target,List<List<Integer>> res,List<Integer> integers,int sum){
//截止条件
if (sum>=target){
if (sum==target){
//因为题目中求的是组合,则例如出现{2,2,3}或者{2,3,2}时,应该认为是同一种组合
List<Integer> tmp = new ArrayList<>(integers);
Collections.sort(tmp);
if (!res.contains(tmp)){
res.add(tmp);
}
}
return;
}
for (int i = 0; i < candidates.length; i++) {
//通过sum记录当前数组integers中元素的总和
sum += candidates[i];
integers.add(candidates[i]);
dfs(candidates,target,res,integers,sum);
sum -= candidates[i];
integers.remove(integers.size()-1);
}
}
执行结果:成功
功能成功实现,但执行用时只击败了5%+的用户,因为递归中出现了很多次不必要的运算.我把优化的点分为以下两个方面:
1、当遍历到数组为{2,2,2,2}时,此时的数组中元素总和已经大于target,所以后续的{2,2,2,3}和{2,2,2,7}没有再遍历的必要。基于这种思路,我们首先需要对传入的数组candidates进行排序,后续判断增加剪枝逻辑
2、当我们的数组candidates排序后,那么也不会出现{2,2,3}和{2,3,2}这种相同的组合了,所以也不需要再判断数组中是否有相同的结果了。
代码如下:
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
Arrays.sort(candidates);
dfs(candidates,target,res,integers,0,0);
return res;
}
/**
* @param candidates 候选数组
* @param target 每减去一个元素,目标值变小
* @param res 结果集列表
* @param integers 当前数组
* @param sum 当前数组元素总和
* @param start 循环遍历起点
*/
public void dfs(int[] candidates,int target,List<List<Integer>> res,List<Integer> integers,int sum,int start){
if (sum==target){
res.add(new ArrayList(integers));
return;
}
for (int i = start; i < candidates.length; i++) {
sum += candidates[i];
//剪枝逻辑
if (sum>target){
sum -= candidates[i];
break;
}
integers.add(candidates[i]);
dfs(candidates,target,res,integers,sum,i);
sum -= candidates[i];
integers.remove(integers.size()-1);
}
}
执行结果:成功