组合求和I和组合求和II的异曲同工分析--得到组合的套路

题目:

组合求和I:对给出的数字target在nums数组中找出和为target的组合,注意nums数组中没有重复的元素,且注意组合中可以出现重复的数字,但不能出现相同的组合。

组合求和II:对给出的数字target在nums数组中找出和为target的组合,注意nums数组中含有重复元素,此次的组合中只是普通的nums的组合数,每个元素不可复用。

解题分析:

组合求和I

首先得让大家清楚求普通组合数的方法:

  1. 写一个递归函数,用for循环把给定的数字遍历。
  2. 递归函数中存在参数pos用于使得下次递归的for循环遍历的数字从下个数字开始,则下个pos=i+1。
  3. 递归函数中存在参数target用于更新每次减少得到的数字,用于判断是否得到组合结果。
  4. 当target==0时得到组合,当target<0明显舍去。

通过以上的普通组合数求和,我们只需要将pos = i即可让组合数中存在重复元素。

组合求和II
在普通组合求和的基础上,由于有重复数字,我们需要去重,我的做法是通过排序让重复的数字挨在一起,然后在每一次换元素进行下一层递归的时候进行一个前面是否有重复的判断。

解题代码(效率都达到过0ms):

组合求和I

class Solution {
public:
    vector<vector<int>>res;
    vector<int>single;
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        dfs(candidates,target,0);
        return res;
    }
private:
//实际就是一个组合的问题,但是这个组合需要特殊改变一下,因为要适应每个元素可以重复,但是组合又不能重复,我们只需要把曾经组合上的参数i+1改为i即可实现每个元素可重复,但是是不同的组合。
    void dfs(vector<int>&candidates,int target,int pos){
        if(target==0){
            res.emplace_back(single);
            return;
        }
        for(int i=pos;i<candidates.size();i++){
            if(target-candidates[i]<0)
                continue;
            single.emplace_back(candidates[i]);
            dfs(candidates,target-candidates[i],i);
            single.pop_back();  
        }
    }
};

组合求和II

class Solution {
public:
    vector<vector<int>>res;
    vector<int>single;
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        //排序用于后面的防止重复操作
        sort(candidates.begin(),candidates.end());
        dfs(candidates,target,0);
        return res;
}
private:
    void dfs(vector<int>&candidates,int target,int pos){
        if(target==0){
            res.emplace_back(single);
            return;
        }
        for(int i=pos;i<candidates.size();i++){
    //若选择i的时候,前面已经选择过和i相同的元素,则跳过该次选择,但是注意之前一定得先排序
    //除了这一个操作和一般的求组和的操作没有任何区别。。
            bool flag = true;
            for(int j=pos;j<i;j++){
                if(candidates[j]==candidates[i]){
                    flag = false;
                    break;
                }
            }
            if(flag){
                if(target-candidates[i]<0)
                return;
            single.emplace_back(candidates[i]);
            dfs(candidates,target-candidates[i],i+1);
            single.pop_back();
        }
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值