Leetcode每日一题——39. 组合总和(回溯)

给定一个无重复元素的数组 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] ]

这是一道涉及回溯算法的题。可以转化为树结构的模型方便理解:

39.组合总和

回溯就会涉及递归,可以参考递归四部曲:

递归作用:从candidates中的下标为startIndex的元素开始取数,一直取到终止条件

递归参数:candidates和target的意义如题意,startIndex表示这一层取数的起始点

终止条件:sum>target和sum==target

单层逻辑:这一层从startIndex开始取数,取一个数后接着下一层从startIndex开始取(因为同一数字可以重复选取,所以不用+1)

代码如下:

class Solution {

    List<Integer> path = null;
    List<List<Integer>> result = null;
    int sum = 0;//记录每一层的和

    void combinationSum1(int[] candidates, int target, int startIndex){
        //递归作用:从candidates中的下标为startIndex的元素开始取数,一直取到终止条件
        //参数:candidates和target的意义如题意,startIndex表示这一层取数的起始点
        //终止条件:sum>target和sum==target
        //单层逻辑:这一层从startIndex开始取数,取一个数后接着下一层从startIndex开始取(因为同一数字可以重复选取,所以不用+1)
        if(sum > target) return;
        if(sum == target){
            result.add(new ArrayList(path));//如果直接result.add(path),那么add进result里的只是path的引用,由于回溯path的内容最终会被清空,那么最后path引用指向的就是空了,那么最后的结果就都是[].所以这里要new一个新的对象
            return;
        }
        for(int i = startIndex; i < candidates.length; i++){//从startIndex开始取
            sum += candidates[i];
            path.add(candidates[i]);
            combinationSum1(candidates, target, i);//如果从0开始取会有重复,比如[2,3],target=5.如果从这里不是startIndex,而是0,那么会有[2,3],[3,2]2个答案重复了。而又因为同一数字可以重复选取,所以不用+1。
            sum -= candidates[i];
            path.remove(path.size() - 1);//回溯,定义操作前的状态为初始状态,操作完后进行初始化
        }
    }

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        path = new ArrayList<>();
        result = new ArrayList<>();
        combinationSum1(candidates, target, 0);//从0开始取第一层的数
        return result;
    }
    
}

回溯算法最大的特点还是在操作完后要初始化这一层的状态(即代码中的path.remove(path.size() - 1);//回溯,定义操作前的状态为初始状态,操作完后进行初始化)。这里是将取数前的状态定义为初始状态了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翔空中,策人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值