LeetCode 39. 组合总和

110 阅读1分钟

39. 组合总和

难度 中等

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例 1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

输入: candidates = [2], target = 1
输出: []

提示:

  • 1 <= candidates.length <= 30
  • 1 <= candidates[i] <= 200
  • candidate 中的每个元素都 互不相同
  • 1 <= target <= 500

题解

这道题本来想用for循环进行枚举的,但是在重复枚举上出现了问题,无法解决重复枚举的问题。去看了官方题解,利用经典的回溯方法,确实解决了重复枚举的问题。利用递归方法搜索结果集,利用回溯方法进行回退。

fig1

这里是官方的搜索树,从根开始都可选和不选。

  • 选,候选下标还是不动,继续尝试枚举当前下标元素
  • 不选,候选下标后移,尝试枚举下个下标元素

这样构成的搜索树可以搜索所有可能的组合,然后我们判断那个组合为target,就是我们要的答案。

class Solution {
    List<List<Integer>> ans = new ArrayList<List<Integer>>();//结果集
    List<Integer> list = new ArrayList<Integer>();//辅助链表
​
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        dfs(candidates, target, 0);//从下标0开始枚举
        return ans;
    }
​
    void dfs(int[] candidates, int target, int idx){
        if(idx == candidates.length){//下标等于候选数组长度,超过了枚举范围
            return ;
        }
        if(target == 0){//找到合适的结果集
            ans.add(new ArrayList<Integer>(list));
            return;
        }
        dfs(candidates, target, idx + 1);//不选当前元素,枚举下个元素
        if(target - candidates[idx] >= 0){//target减去候选元素还大于0
            list.add(candidates[idx]);//入队
            dfs(candidates, target - candidates[idx], idx);//继续枚举当前元素
            list.remove(list.size() - 1);//出队
        }
    }
}