力扣 leetcode 40. 组合总和 II

问题描述

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

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

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

提示:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

示例

示例 1:

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

示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

解题思路

基本思路参照力扣 leetcode 39. 组合总和,这里添加的限制是数组中每个元素只能使用一次。因此,我们要避免两种重复:一是重复使用同一个数组元素;二是上一轮遍历时使用的元素与这一轮遍历时使用的元素的值相同。

在之前代码的基础上,我们稍作修改,用一个变量 pre 来记录上一轮遍历时所用的数组元素的值,避免重复。

class Solution {
public:

    void pushItem(vector<int>& candidates, vector<vector<int>>& res, int target, vector<int>& r, int n, int idx){
        if(!target){ // 保存结果
            vector<int> tmp(n);
            for(int i = 0; i < n; i++){
                tmp[i] = r[i];
            }
            res.push_back(tmp);
            return;
        }
        int pre = -1;
        for(int i = idx; i < candidates.size(); i++){
            if(pre == candidates[i]){ // 如果此次遍历时,元素与上一轮相同,那么就是重复的,应该跳过
                continue;
            }
            if(candidates[i] <= target){
                if(n < r.size()){
                    r[n] = candidates[i];
                }
                else{
                    r.emplace_back(candidates[i]);
                }
                pushItem(candidates, res, target - candidates[i], r, n + 1, i + 1);
                pre = candidates[i];
            }
            else{
                break;
            }
        }
    }

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        vector<int> r;
        vector<vector<int>> res;
        pushItem(candidates, res, target, r, 0, 0);
        return res;
    }
};
posted @ 2022-12-09 00:09  greatestchen  阅读(18)  评论(0编辑  收藏  举报