LeetCode 组合总和
作者:互联网
LeetCode 组合总和
给定一个无重复元素的数组 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]
]
提示:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都是独一无二的。
1 <= target <= 500
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
List<Integer> subList = new ArrayList<Integer>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
dfs(candidates,0,0,target);
return list;
}
public void dfs(int[] candidates,int x,int step,int target){
/*
如果没有对数组进行排序,并且下面的for循环中没有判断target - candidates[i] < 0这一步的时候
那么就需要有这一步。因为存在[2,7,6,3,5,1],target = 9的例子,如果下面的for循环中有if判断,
但是没有对数组进行排序的时候,那么就会发生报错,因为根据代码,就会发现缺少了诸如[2,6,1]这
样的结果,错误原因就在于没有在对数组进行排序的时候,就利用target - candidates[i]是否小于0
来判断是否可以结束程序,返回到上一层递归中
if(target < 0)
return;
*/
if(target == 0){
//当target == 0的时候,说明subList满足和为target
list.add(new ArrayList<Integer>(subList));
return;
}
int i;
for(i = x; i < candidates.length; i++){
/*
如果减去candidates[i]之后小于0,由于数组升序排序的,后面的数只会比candidates[i]大,所
直接返回所以,如果没有这一步进行判断的话,那么可以不进行排序,只是进行循环之前判断
target是否小于0,如果是,直接返回
*/
if(target - candidates[i] < 0)
return;
subList.add(candidates[i]);
dfs(candidates,i,step + 1,target - candidates[i]);//由于一个数字可以重复使用,所以下次递归的时候,依旧是从i下标开始的
subList.remove(step);
}
}
}
运行结果:
LeetCode 组合总和II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
提示:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum-ii
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
List<Integer> subList = new ArrayList<Integer>();
int result;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
dfs(candidates,0,0,target);
return list;
}
public void dfs(int[] candidates,int x,int step,int target){
//step用于删除列表的最后一个元素
if(result == target){
list.add(new ArrayList<Integer>(subList));
return;
}
int i;
/*
这是正常的深度优先搜索的情况,每一次都是从下标为0开始遍历,为了标记哪些元素已经访问
过了,所以定义一个boolean数组,在判断是否可以放入到列表的时候,需要判断当前下标i已经
被访问过了,或者虽然下标i对应的数没有被访问过,但是前一个数字 i - 1对应的数字
candidates[ i - 1] == candidates[i],并且visited[i - 1]重新置为了false,说明此时
candidates[i]已经将值为candidates[i]的所有情况都枚举了,所以利用continue结束本次循
环。
但是这样提交之后,就会发现会有错误,例如[1,1,2,5,7],target = 7,那么这样每次递归都是
从0开始,从而导致了会出现重复的例子,例如[1,2,5],[1,5,2],这并不是会因为数组已经排序
了就可以避免重复的。因此,解决的办法是在将当前i放入到列表之后,下一个放入到列表中的元
素是在i后面,也即dfs(candidates,i + 1,step + 1,target),并且for循环中i初始值是形式参
数x
也正因如此,每次递归的时候访问到的元素都是没有访问过的,所以if判断也就没有必要写上
visited[i]了.同时由于我们没有在if判断中写上visited[i]这一个判断,所以表明了visited
的值对我们程序来说并没有什么实际意义,所以不需要对其进行赋值,之后再重置,所以也就影响
到了i > 0 && candidates[i] == candidates[i - 1] && !visited[i - 1],所以整个if判断
就变成了if(i > x && candidates[i] == candidates[i - 1])
for(i = 0; i < candidates.length; i++){
if(visited[i] || i > 0 && candidates[i] == candidates[i - 1] && !visited[i - 1])
continue;
if(result + candidates[i] > target)
return;
subList.add(candidates[i]);
result += candidates[i];
visited[i] = true;
dfs(candidates,i + 1,step + 1,target);
subList.remove(step);
visited[i] = false;
result -= candidates[i];
}
*/
for(i = x; i < candidates.length; i++){
/*
由于数组存在重复元素的情况,所以在将数组排序之后,如果当前下标i的数和i - 1对应的值
相等,那么下标为i - 1的数已经将下标为i的所有情况都考虑了,所以利用continue结束本次循环
所以判断的条件是i > x && candidates[i] == candidates[i - 1]。这样也可以理解为
candidates[i]和candidates[i - 1]对应的target相等的时候,candidates[i - 1]已经将
candidates[i]的所有情况都考虑了,所以就没有必要再进行枚举candidates[i - 1]了
*/
if(i > x && candidates[i] == candidates[i - 1])
continue;
/*
如果当前的result + candidates[i] 大于了target,由于candidates数组已经排序了,那
么i后面的值一定大于candidates[i],所以result加上后面的值也会大于target,所以就
没有必要再递归下去了,直接返回到上一层递归。
*/
if(result + candidates[i] > target)
return;
subList.add(candidates[i]);
result += candidates[i];
dfs(candidates,i + 1,step + 1,target);
subList.remove(step);
result -= candidates[i];
}
}
}
运行结果:
标签:target,组合,int,subList,step,candidates,result,LeetCode,总和 来源: https://blog.csdn.net/weixin_46544385/article/details/118884533