2957 字
约 9 分钟
8
LeetCode刷题Java版040.组合总和 II
无标签

LeetCode刷题Java版040.组合总和 II

作者:沉默王二
发布时间:2022-09-13T11:30:05.956+0800


040.组合总和 II

题意

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。

难度

中等

示例

输入: candidates = [10,1,2,7,6,1,5], target = 8,

[[1,1,6],[1,2,5],[1,7],[2,6]]

分析

本题跟 039.组合总和 最大的差别就在于——同一个数字不能被重复选择,但是candidates中可能会存在有重复的数字。

因为candidates中的先后顺序并不会影响答案,而且如果有重复元素的话放在一起也会更有利于解题,所以,我们先把candidates排序一遍。

排序之后就可以看出一些端倪了。

如果有数字出现两次或两次以上,那么在我们递归到第step步的时候,需要从begin-(candidates.length - 1)中选择一个元素,然后继续向下递归选择下一个元素。

但是,如果现在要选的元素——也就是candidates[i],和candidates[i - 1]一样大概怎么办呢?

直接选择,然后递归下去?

看下图,这是一棵简单的由递归搜索形成的部分解答树:

我们发现,答案重复出现了。

出现的原因,就是因为我们在选择第三个数字的时候,有[2,2]的存在,导致第三个数字重复了,所以,如果一个数字跟上一个一样,这个数字是可以直接跳过的。

那为什么之前的1可以被连续选择呢?

因为我们在选择第二个1的时候,已经到了 第二步 ,是选择了第一个1的后续状态,而并非选择第一个1的平行状态。而第二个2的选择,则是和第一个2处于平行状态,也就是递归的同一层。

所以,这道题便迎刃而解了。我们只需要先排序,然后在枚举的时候,过滤掉相同的,然后找寻下一个即可。

class Solution {

    private void DFS(List nowSta,int target, int tot, int begin, int[] candidates){        if(tot == target){            res.add(new ArrayList<>(nowSta));            return ;        }        for(int i = begin;i < candidates.length;i++){            if(tot + candidates[i] > target)                continue;            if(i != begin && candidates[i] == candidates[i - 1])                continue;            nowSta.add(candidates[i]);            DFS(nowSta,target,tot + candidates[i],i + 1,candidates);            nowSta.remove(nowSta.size() - 1);        }    }    public List<List> combinationSum2(int[] candidates, int target) {        Arrays.sort(candidates);        List sta = new ArrayList<>();        DFS(sta,target,0,0,candidates);        return res;    }}

表现也很不错

时间复杂度的上界是:

因为每个数字都有选或者不选两个状态,还有最后将这些合法答案加入总方案中的时间,所以是,再加上一开始的排序操作,总的时间复杂度的上界是上述的式子,但是,因为可以过滤掉总和超过target的部分,以及重复选择同个数字的部分,所以实际上的运行时间肯定是远远低于上限的。

总结

本题仍然是一道递归搜索的题目,这类题目的思路通常都能非常快的想出来,因为和我们平时的思考过程非常类似,重点在于如何优化搜索和枚举的时间,如果能细心分析,找到题目中的特殊性质,就能把这类题目解决。

力扣链接:https://leetcode.cn/problems/combination-sum-ii/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 780 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

040.组合总和 II

题意

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。

难度

中等

示例

输入: candidates = [10,1,2,7,6,1,5], target = 8,

[[1,1,6],[1,2,5],[1,7],[2,6]]

分析

本题跟 039.组合总和 最大的差别就在于——同一个数字不能被重复选择,但是candidates中可能会存在有重复的数字。

因为candidates中的先后顺序并不会影响答案,而且如果有重复元素的话放在一起也会更有利于解题,所以,我们先把candidates排序一遍。

排序之后就可以看出一些端倪了。

如果有数字出现两次或两次以上,那么在我们递归到第step步的时候,需要从begin-(candidates.length - 1)中选择一个元素,然后继续向下递归选择下一个元素。

但是,如果现在要选的元素——也就是candidates[i],和candidates[i - 1]一样大概怎么办呢?

直接选择,然后递归下去?

看下图,这是一棵简单的由递归搜索形成的部分解答树:

我们发现,答案重复出现了。

出现的原因,就是因为我们在选择第三个数字的时候,有[2,2]的存在,导致第三个数字重复了,所以,如果一个数字跟上一个一样,这个数字是可以直接跳过的。

那为什么之前的1可以被连续选择呢?

因为我们在选择第二个1的时候,已经到了 第二步 ,是选择了第一个1的后续状态,而并非选择第一个1的平行状态。而第二个2的选择,则是和第一个2处于平行状态,也就是递归的同一层。

所以,这道题便迎刃而解了。我们只需要先排序,然后在枚举的时候,过滤掉相同的,然后找寻下一个即可。

class Solution {

    private void DFS(List nowSta,int target, int tot, int begin, int[] candidates){        if(tot == target){            res.add(new ArrayList<>(nowSta));            return ;        }        for(int i = begin;i < candidates.length;i++){            if(tot + candidates[i] > target)                continue;            if(i != begin && candidates[i] == candidates[i - 1])                continue;            nowSta.add(candidates[i]);            DFS(nowSta,target,tot + candidates[i],i + 1,candidates);            nowSta.remove(nowSta.size() - 1);        }    }    public List<List> combinationSum2(int[] candidates, int target) {        Arrays.sort(candidates);        List sta = new ArrayList<>();        DFS(sta,target,0,0,candidates);        return res;    }}

表现也很不错

时间复杂度的上界是:

因为每个数字都有选或者不选两个状态,还有最后将这些合法答案加入总方案中的时间,所以是,再加上一开始的排序操作,总的时间复杂度的上界是上述的式子,但是,因为可以过滤掉总和超过target的部分,以及重复选择同个数字的部分,所以实际上的运行时间肯定是远远低于上限的。

总结

本题仍然是一道递归搜索的题目,这类题目的思路通常都能非常快的想出来,因为和我们平时的思考过程非常类似,重点在于如何优化搜索和枚举的时间,如果能细心分析,找到题目中的特殊性质,就能把这类题目解决。

力扣链接:https://leetcode.cn/problems/combination-sum-ii/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 780 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

040.组合总和 II

题意

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。

难度

中等

示例

输入: candidates = [10,1,2,7,6,1,5], target = 8,

[[1,1,6],[1,2,5],[1,7],[2,6]]

分析

本题跟 039.组合总和 最大的差别就在于——同一个数字不能被重复选择,但是candidates中可能会存在有重复的数字。

因为candidates中的先后顺序并不会影响答案,而且如果有重复元素的话放在一起也会更有利于解题,所以,我们先把candidates排序一遍。

排序之后就可以看出一些端倪了。

如果有数字出现两次或两次以上,那么在我们递归到第step步的时候,需要从begin-(candidates.length - 1)中选择一个元素,然后继续向下递归选择下一个元素。

但是,如果现在要选的元素——也就是candidates[i],和candidates[i - 1]一样大概怎么办呢?

直接选择,然后递归下去?

看下图,这是一棵简单的由递归搜索形成的部分解答树:

我们发现,答案重复出现了。

出现的原因,就是因为我们在选择第三个数字的时候,有[2,2]的存在,导致第三个数字重复了,所以,如果一个数字跟上一个一样,这个数字是可以直接跳过的。

那为什么之前的1可以被连续选择呢?

因为我们在选择第二个1的时候,已经到了 第二步 ,是选择了第一个1的后续状态,而并非选择第一个1的平行状态。而第二个2的选择,则是和第一个2处于平行状态,也就是递归的同一层。

所以,这道题便迎刃而解了。我们只需要先排序,然后在枚举的时候,过滤掉相同的,然后找寻下一个即可。

class Solution {

    private void DFS(List nowSta,int target, int tot, int begin, int[] candidates){        if(tot == target){            res.add(new ArrayList<>(nowSta));            return ;        }        for(int i = begin;i < candidates.length;i++){            if(tot + candidates[i] > target)                continue;            if(i != begin && candidates[i] == candidates[i - 1])                continue;            nowSta.add(candidates[i]);            DFS(nowSta,target,tot + candidates[i],i + 1,candidates);            nowSta.remove(nowSta.size() - 1);        }    }    public List<List> combinationSum2(int[] candidates, int target) {        Arrays.sort(candidates);        List sta = new ArrayList<>();        DFS(sta,target,0,0,candidates);        return res;    }}

表现也很不错

时间复杂度的上界是:

因为每个数字都有选或者不选两个状态,还有最后将这些合法答案加入总方案中的时间,所以是,再加上一开始的排序操作,总的时间复杂度的上界是上述的式子,但是,因为可以过滤掉总和超过target的部分,以及重复选择同个数字的部分,所以实际上的运行时间肯定是远远低于上限的。

总结

本题仍然是一道递归搜索的题目,这类题目的思路通常都能非常快的想出来,因为和我们平时的思考过程非常类似,重点在于如何优化搜索和枚举的时间,如果能细心分析,找到题目中的特殊性质,就能把这类题目解决。

力扣链接:https://leetcode.cn/problems/combination-sum-ii/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 780 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

            知识星球
            
    
    
        
        扫码加入星球
        查看更多优质内容
    
    https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412
LeetCode刷题Java版040.组合总和 II
https://clxhxhhr.top/posts/2504/
作者
clxstart
发布于
2026-09-19
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。