• LeetCode.39. 组合总和


    LeetCode.39. 组合总和

    难度:medium

     

    Java:

    跳出的条件有两个,sum > target 和 sum == target;

    本题还需要startIndex来控制for循环的起始位置,对于组合问题,什么时候需要startIndex呢?

    举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:77.组合 (opens new window)216.组合总和III (opens new window)

    如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:17.电话号码的字母组合

    未剪枝:

     

    1. class Solution {
    2. List> ans = new ArrayList>();
    3. List path = new ArrayList<>();
    4. int sum = 0;
    5. public List> combinationSum(int[] candidates, int target) {
    6. backTracking(candidates, target, 0);
    7. return ans;
    8. }
    9. // startIndex控制选取元素的范围,出现只是元素顺序不同的组合
    10. public void backTracking(int[] candidates, int target, int startIndex) {
    11. if (sum > target) {
    12. return;
    13. }
    14. if (sum == target) {
    15. ans.add(new ArrayList<>(path));
    16. return;
    17. }
    18. for (int i = startIndex; i < candidates.length; i++) {
    19. sum += candidates[i];
    20. path.add(candidates[i]);
    21. // startIndex = i,表明可以重复选取当前元素
    22. backTracking(candidates, target, i);
    23. sum -= candidates[i];
    24. path.remove(path.size() - 1);
    25. }
    26. }
    27. }

     剪枝方法:

    以及上面的版本一的代码大家可以看到,对于sum已经大于target的情况,其实是依然进入了下一层递归,只是下一层递归结束判断的时候,会判断sum > target的话就返回。

    其实如果已经知道下一层的sum会大于target,就没有必要进入下一层递归了。

    那么可以在for循环的搜索范围上做做文章了。

    对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历

    1. class Solution {
    2. List> ans = new ArrayList>();
    3. List path = new ArrayList<>();
    4. int sum = 0;
    5. public List> combinationSum(int[] candidates, int target) {
    6. // 需要排序
    7. Arrays.sort(candidates);
    8. backTracking(candidates, target, 0);
    9. return ans;
    10. }
    11. // startIndex控制选取元素的范围,出现只是元素顺序不同的组合
    12. public void backTracking(int[] candidates, int target, int startIndex) {
    13. if (sum == target) {
    14. ans.add(new ArrayList<>(path));
    15. return;
    16. }
    17. for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) {
    18. sum += candidates[i];
    19. path.add(candidates[i]);
    20. // startIndex = i,表明可以重复选取当前元素
    21. backTracking(candidates, target, i);
    22. sum -= candidates[i];
    23. path.remove(path.size() - 1);
    24. }
    25. }
    26. }

    复杂度分析:

    • 时间复杂度:O(S),其中 S 为所有可行解的长度之和。
    • 空间复杂度:O(n),n为递归的深度
  • 相关阅读:
    物联网虚拟仿真实验教学中心平台建设
    推荐十个优秀的ASP.NET Core第三方中间件,你用过几个?
    【MAC】升级 Mac os 后报错
    Java第7章 类的高级特性
    【Redis】高效保障MySQL和Redis的数据一致性?
    【基于C的排序算法】插入排序之希尔排序
    计算机系统概论
    fastadmin插件 shopro 商城支付配置
    Node.js的基本概念&&node -v 和npm -v 这两个命令的作用
    Docker从认识到实践再到底层原理(九)|Docker Compose 容器编排
  • 原文地址:https://blog.csdn.net/weixin_45867071/article/details/126344360