39 组合总和(dfs)

1. 问题描述:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum

2. 思路分析:

① 从题目中可以看出存在一个明显的特点,在凑成目标数字的过程中其实是在不断尝试可能的方案,比如第一个测试用例中目标数字为7其中一种为两个2和一个3但是我们实际上是估计不出来究竟使用多少个2与多少个3去凑或者估计出来很难使用常规的方法来凑,而dfs恰恰可以解决这个问题,因为dfs最适合这种题目,在不知道的情况下逐个可能的方案去尝试,直到达到目标数字或者是所有的递归方法都执行完成,所以使用dfs来解决就非常合适了

② 对于dfs来求解我们可以先画一下图,描述一下递归的过程,这个也就类似于二叉树的递归遍历类似的,下面使用Word画了一下图(很粗糙简单,还有些剩余的没有画上),画出递归树的目的是为了更好理解整个的过程并且可以清楚确定递归方法中某些参数传值问题,这道题目由于要求是不能够重复的,所以我们在循环中递归的话需要循环变量从当前的位置开始而不是从零开始,因为我只能加上自己位置的数字以及自己位置之后的数字这样得出的结果才不是重复的,假如从零开始的话那么的出来的结果很多是重复的,所以在传递递归的位置的时候需要将当前的位置传递过去,这个可以结合递归树会更好理解一点

③ 由于递归的话耗时是比较大的,所以需要提前进行剪枝,我们在一开始的时候可以对数组进行排序,这样在循环中进行递归的话可以提前进行判断,例如当发现加上当前位置的值之后太大了这样就可以break掉了,因为后面的数字就更大了

④ 可以使用栈或者是双端队列来存储中间得到的过程,使用栈来存储的话可以之间将栈中的元素加入到ArrayList中,不要使用List来存储中间的过程,因为List再加入元素的时候假如后面有修改的话List里面的元素也是跟着改变的,假如需要使用List的话需要在递归出口遍历List,使用另外一个List来加入这些元素,总的来说最好使用栈或者是双端队列来处理中间得到目标数字的过程

3. 代码如下:

import java.util.*;
public class Solution {
    List<List<Integer>> res = new ArrayList<>();
    int len = 0;
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        /*先要对数组进行排序可以减少时间复杂度*/
        Arrays.sort(candidates);
        len = candidates.length;
        recursion(candidates, target, 0, 0, new Stack());
        return res;
    }

    /*第三个参数是之前各个元素的累加和, 第四个参数表示的是当前递归的位置*/
    private void recursion(int[] candidates, int target, int cur, int pos, Stack stack) {
        if (cur == target) {
            res.add(new ArrayList<>(stack));
            return;
        }
        for (int i = pos; i < len; ++i){
            /*剪枝, 当前元素都大于了target肯定之后的元素更是加起来大于了target这个剪枝对于提升效率是很有帮助的*/
            if (cur + candidates[i] > target) break;
            stack.add(candidates[i]);
            recursion(candidates, target, cur + candidates[i], i, stack);
            /*回溯*/
            stack.pop();
        }
    }
}
发布了569 篇原创文章 · 获赞 153 · 访问量 59万+

猜你喜欢

转载自blog.csdn.net/qq_39445165/article/details/105396709