Leetcode 40. Combination Sum II

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

s思路:
1. 和39题区别就是,这次要考虑在nums里有重复的数了,并且每个数字只能使用一次!问题是:如何检测重复的case,并机智的skip?例如,

nums=[1,1,2,5,6,7,10 ], target=8

当找到所有包含第一个1的组合后,例如:[1,7],[1,1,6],[1,2,5],来到第二个1,此时以1开头的一定已经找到了,所以直接跳过。但问题是,在找包含第一个1的组合[1,1,6],还是用到了第二个1,也就是:重复的数如果作为组合开头的数,就需要skip;重复的数在组合中间,则不能skip。
2. 再深度分析一下:为什么如下条件就可以排除重复情况呢?

i>0&&candidates[i]==candidates[i-1]&&i!=idx

关键是为什么i!=idx?原因:由于backtracking=for+recursive,recursive每次进入下一个层次,而for在本层次一个一个的尝试,idx是每个recursive入口,i是for的循环变量,并初始化为idx,当idx==i,说明此时刚进入这一层,即:这一层的第一个尝试,而i增加后,idx!=i,此时表示在这一层已经尝试过至少一个,如果加上candidates[i]==candidates[i-1],则说明以i开头的组合必定出现在以i-1开头的组合中,所以不需要再尝试,直接skip。

class Solution {
public:
    void helper(vector<int>& candidates, int target,vector<vector<int>>&res,vector<int> cur,int idx){
        if(target==0){
            res.push_back(cur);
            return; 
        }

        for(int i=idx;i<candidates.size();i++){
            if(target<candidates[i]) break;
            if(i>0&&candidates[i]==candidates[i-1]&&i!=idx) continue;
            //上面是用来排除重复的情况。当前的数和前一个数相等,且当前数作为组合开头的数
            cur.push_back(candidates[i]);
            helper(candidates,target-candidates[i],res,cur,i+1);//i+1
            cur.pop_back();
        }
    }

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        //
        sort(candidates.begin(),candidates.end());
        vector<vector<int>> res;
        //vector<int> cur;
        helper(candidates,target,res,{},0);//{}表示vector,""表示string
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值