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]

]

 

题目的意思:

从1到n中随机选取几个数,让其和等于m根据这句话,选出来的数可以重复,且选取的个数任意,但是不能包含重复的组合

所以也可以利用深度优先搜索【DFS】+回溯来解决

其中深度优先搜索算法用来寻找所有可能的组合,而回溯是用来筛选出所有可能组合中的可行解【如果发现某候选解不是可行解,直接丢弃】

注:在进行深搜时,下一次深搜应从当前元素继续往后看【其中从当前元素开始继续找的话既保证了元素可以重复,又不会造成最终的组合重复】

步骤:

1.从第一个元素开始相加

2.让局部和继续累加候选的剩余值

3.局部和等于目标值,保存组合,向上回退,寻找其它组合

 

//深搜+回溯
public class combinationSum {
    private List<List<Integer>> res = new ArrayList<>();
    private List<Integer> list = new ArrayList<>();

    public List<List<Integer>> combinationSum1(int[] candidates, int target) {
        if (candidates == null || candidates.length == 0) {
            return res;
        }
        backTrace(candidates, 0, target, 0);
        return res;
    }

    private void backTrace(int[] candidates, int sum, int target, int beginIndex) {
        //边界条件,如果大于等于目标值,就结束【因为此时的和已经大于或等于目标值了,再继续深搜只会让和更加大于目标值,而这样的组合明显不合题意】
        if (sum >= target) {
            //如果等于目标值,表示找到一种组合,放入最终集合中
            if (sum == target) {
                res.add(new ArrayList<>(list));
            }
            return;
        }

        for (int i = beginIndex; i < candidates.length; i++) {
            //如果当前元素大于目标值,直接跳过
            if (candidates[i] > target) {
                continue;
            }
            list.add(candidates[i]);
            //从当前元素开始往后看【因为元素可以重复】
            backTrace(candidates, sum + candidates[i], target, i);   //区别:beginIndex为当前元素的下标!!!
            //回溯,向上回退,寻找下一种组合
            list.remove(list.size() - 1);
        }
    }

    //candidates = [2,3,6,7], target = 7
    // 从2开始深搜:
    //   2<7 -> 2+2<7 -> 2+2+2<7 -> 2+2+2+2>7【丢弃最后一个2,且不再 在2+2+2+2的基础上深搜】 -> 2+2+2+3>7【丢弃3,且不再 在2+2+2+3的基础上深搜】
    //       -> 2+2+2+6>7【丢弃6,且不再 在2+2+2+6的基础上深搜】 -> 2+2+2+7>7【丢弃7,且不再 在2+2+2+7的基础上深搜】
    //       -> 丢弃最后一个2【2+2+2的深搜完毕】
    //       -> 2+2+3==7【找到一种组合,存入最终结果】 -> 丢弃3【2+2+3的深搜完毕】
    //       -> 2+2+6>7【丢弃6,2+2+6的深搜完毕】
    //       -> 2+2+7>7【丢弃7,2+2+7的深搜完毕】
    //       -> 丢弃最后一个2【2+2的深搜完毕】
    //       -> 2+3<7 -> 2+3+3>7【丢弃最后一个3,且不再 在2+3+3的基础上深搜】 -> 2+3+6>7【丢弃6,且不再 在2+3+6的基础上深搜】
    //       -> 2+3+7>7【丢弃7,且不再 在2+3+7的基础上深搜】
    //       -> 丢弃3【2+3的深搜完毕】
    //       -> 2+6>7【丢弃6,2+6的深搜完毕】
    //       -> 2+7>7【丢弃7,2+7的深搜完毕】
    //       -> 丢弃2【2的深搜完毕】
    // 从3开始深搜:
    //   3<7 -> 3+3<7 -> 3+3+3>7【丢弃最后一个3,且不再 在3+3+3的基础上深搜】 -> 3+3+6>7【丢弃6,且不再 在3+3+6的基础上深搜】
    //       -> 3+3+7>7【丢弃7,且不再 在3+3+7的基础上深搜】
    //       -> 丢弃最后一个3【3+3的深搜完毕】
    //       -> 3+6>7【丢弃6,3+6的深搜完毕】
    //       -> 3+7>7【丢弃7,3+7的深搜完毕】
    //       -> 丢弃3【3的深搜完毕】
    // 从6开始深搜:
    //   6<7 -> 6+6>7【丢弃最后一个6,且不再 6+6的基础上继续深搜】 -> 6+7>7【丢弃7,且不再 6+7的基础上继续深搜】
    //       -> 丢弃6【6的深搜完毕】
    // 从7开始深搜:
    //   7==7【找到一种组合,存入最终结果】
    //       -> 丢弃7【7的深搜完毕】
    // 数组candidates的元素已全部遍历完
    //最终结果:[[2,2,3],[7]]
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值