题目地址(39. 组合总和)

https://leetcode-cn.com/problems/combination-sum/

题目描述

  1. 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 所有不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
  2. candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
  3. 对于给定的输入,保证和为 target 的不同组合数少于 150 个。
  4. 示例 1
  5. 输入:candidates = [2,3,6,7], target = 7
  6. 输出:[[2,2,3],[7]]
  7. 解释:
  8. 2 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
  9. 7 也是一个候选, 7 = 7
  10. 仅有这两种组合。
  11. 示例 2
  12. 输入: candidates = [2,3,5], target = 8
  13. 输出: [[2,2,2,2],[2,3,3],[3,5]]
  14. 示例 3
  15. 输入: candidates = [2], target = 1
  16. 输出: []
  17. 示例 4
  18. 输入: candidates = [1], target = 1
  19. 输出: [[1]]
  20. 示例 5
  21. 输入: candidates = [1], target = 2
  22. 输出: [[1,1]]
  23. 提示:
  24. 1 <= candidates.length <= 30
  25. 1 <= candidates[i] <= 200
  26. candidate 中的每个元素都 互不相同
  27. 1 <= target <= 500

前置知识


公司

  • 暂无

思路

本题还需要startIndex来控制for循环的起始位置,对于组合问题,什么时候需要startIndex呢?
我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:77.组合,216.组合总和III。
如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:17.电话号码的字母组合
image.png
这题和之前有两点不同:

  • 组合没有数量要求
  • 元素可无限重复选取

    关键点


代码

  • 语言支持:Java

Java Code:

class Solution {
        ArrayList<List<Integer>> res = new ArrayList<>();
        ArrayList<Integer> path = new ArrayList<>();
        //candidates是给定的整数数组 , target是目标数字
        public List<List<Integer>> combinationSum(int[] candidates, int target) {
            //先排序 方便后面如果sum大于target的话 就把她后面的都剪掉
            Arrays.sort(candidates);
            loop(candidates,target,0,0);
            return res;
        }
        //candidates是给定的整数数组 , target是目标数字 startIndex是循环开始的位置 num是path相加的总和
        void loop(int[] candidates, int target ,int startIndex,int num){
            //终止条件
            if (target == num) {
                res.add(new ArrayList<>(path));
                return;
            }
            for (int i = startIndex; i < candidates.length; i++) {
                //剪枝
                //如果总和加上下一个数字大于目标 就跳过当前循环 因为排好序了 所以return即可 这里题解给的是break 感觉没什么意义
                if(num+ candidates[i] >target) {
                    return;
                }
                path.add(candidates[i]);
                num += candidates[i];
                //因为规定可以有重复的数字 所以下一次递归的时候还是从0开始
                loop(candidates, target, 0, num);
                //回溯
                path.remove(path.size()-1);
                num -= candidates[i];
            }
        }
    }

复杂度分析

令 n 为数组长度。

  • 时间复杂度:39. 组合总和 - 图2#card=math&code=O%28n%29&id=KePvH)
  • 空间复杂度:39. 组合总和 - 图3#card=math&code=O%28n%29&id=tgg0o)