【Leetcode每日一题】2020-09-09 40 组合总和 II - 中等 (Python & C++)

来源:力扣

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次

说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
Each number in candidates 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.

示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]

思路:回溯算法 + 剪枝
leetcode 官方题解

Python:

def combinationSum2(candidates, target):
    ans, combine, freq = [], [], []
    candidates.sort()
    for num in candidates:
        if not freq or num > freq[-1][0]:
            freq.append([num, 1])
        else:
            freq[-1][1] += 1
    def dfs(target, idx):
        if target == 0:
            ans.append(combine[:])
            return
        if idx >= len(freq):
            return
        dfs(target, idx+1)

        most = min(target/freq[idx][0], freq[idx][1])
        for i in range(1, most+1):
            combine.append(freq[idx][0])
            dfs(target-i*freq[idx][0], idx+1)
        for i in range(1, most+1):
            combine.pop()
    dfs(target, 0)
    return ans

C++:

vector<pair<int, int>> freq;
vector<vector<int>> res;
vector<int> combine;

void dfs(vector<int>& candidates, int target, int idx)
{
    if (target == 0)
    {
        res.emplace_back(combine);
        return;
    }
    if (idx >= freq.size())
    {
        return;
    }
    dfs(candidates, target, idx+1);
    int most = min(target/freq[idx].first, freq[idx].second);
    for (int i = 1; i <= most; ++i)
    {
        combine.emplace_back(freq[idx].first);
        dfs(candidates, target-i*freq[idx].first, idx+1);        
    }
    for (int i = 1; i <= most; ++i)
    {
        combine.pop_back();
    }
}

vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
    sort(candidates.begin(), candidates.end());
    for (auto num : candidates)
    {
        if (freq.empty() || num > freq.back().first)
        {
            freq.emplace_back(num, 1);
        }
        else
        {
            ++freq.back().second;
        }
    }
    dfs(candidates, target, 0);
    return res;
}


/***************************************************************/
// 也可以使用上一篇每日一题里的回溯算法
void dfs(vector<int>& candidates, vector<vector<int>>& res, vector<int>& combine, int target, int idx)
{
    if (target == 0)
    {   
        // 因为要求不能重复,所以要检查是否重复
        if (find(res.begin(), res.end(), combine) == res.end())
        {
            res.emplace_back(combine);
            return;
        }
    }
    if (idx >= candidates.size()) return;

    dfs(candidates, res, combine, target, idx+1);

    if (target - candidates[idx] >= 0)
    {    
        combine.emplace_back(candidates[idx]);
        // 因为要求candidates里的每个数只能被用一次,所以这里要用idx+1
        dfs(candidates, res, combine, target-candidates[idx], idx+1);
        combine.pop_back();
    }
}

vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
    vector<vector<int>> res;
    vector<int> combine;
    // 提前对candidates进行排序,这样可以保证结果都是递增的
    sort(candidates.begin(), candidates.end());
    dfs(candidates, res, combine, target, 0);
    return res;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值