C/C++教程

LeetCode 组合总和

本文主要是介绍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];
            }
    }
}

运行结果:
在这里插入图片描述

这篇关于LeetCode 组合总和的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!