当前位置: 首页 > article >正文

组合总和II(回溯、去重)

40. 组合总和 II - 力扣(LeetCode)

题目描述

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

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

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

样例输入

示例 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]
]

提示:

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

题解

本题与该题组合总和(回溯)-CSDN博客的区别在于,candidates 候选集合中有重复的元素,然而解集中要求不能包含重复的组合,因此在求解时要对解集进行去重

举个例子,如下图,当candidates = [10,1,2,7,6,1,5],target=8时,显然[1,7]是一个解集,但是candidates 存在两个元素1,也就是图中指针a和指针c指向的元素,如果我们使用回溯法进行遍历,势必会出现两个解集[1,7],一个是[a,b],另一个是[b,c],但他们都是解集[1,7],这是不符合题意的。

关于去重 

首先我们对candidates 数组进行排序,得到如下序列:

其次,使用回溯法遍历排序后的candidates,如果遇到相邻相同的元素(candidates[i-1]==candidates[i]),跳过即可。

那么接下来的问题就转换成了,如何在回溯法中模拟这个过程?

为方便说明问题,我们假定candidates =[1,1,2],target=3.

如下图所示,排序后的candidates,如果遇到相邻的相同元素,则必有candidates[i-1]==candidates[i],但问题在于这种情况在同一树枝下深度的遍历和同一层的横向遍历都会发生,而我们要的去重是同一树层的去重,也就是在同一层的遍历下,遇到candidates[i-1]==candidates[i]就跳过。

为区别这两种情况,我们使用一个used辅助数组,记录每次取数的过程,也就是说,如果每次取到了一个数,就将used的对应位置置为true。

在下图中可以看出在candidates[i] == candidates[i - 1]相同的情况下:

used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
used[i - 1] == false,说明同一树层candidates[i - 1]使用过

故满足我们要求的去重过程可表示为

如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]。

此时for循环里就应该做continue的操作。

为什么 used[i - 1] == false 就是同一树层呢,因为同一树层,used[i - 1] == false 才能表示,当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。而 used[i - 1] == true,说明是进入下一层递归,去下一个数,所以是树枝上

详细题解过程参考:40. 组合总和 II - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/combination-sum-ii/solutions/857552/dai-ma-sui-xiang-lu-dai-ni-xue-tou-hui-s-ig29/

代码

class Solution {
private:
    vector<int> path;
    vector<vector<int>> res;
public:
    void backing(vector<int>& candidates,int target,int startIndex,int curSum,vector<bool>& used)
    {
        if(curSum>target) return;
        if(curSum==target)
        {
            res.push_back(path);
            return;
        }

        for(int i=startIndex;i<candidates.size() && curSum+candidates[i]<=target;i++)
        {
            if(i>0 && candidates[i-1]==candidates[i] && used[i-1]==false)
            {
                continue;
            }
            else
            {
                curSum+=candidates[i];
                used[i]=true;
                path.push_back(candidates[i]);
                backing(candidates,target,i+1,curSum,used);
                path.pop_back();
                curSum-=candidates[i];
                used[i]=false;
            }
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<bool> used(candidates.size(),0);
        backing(candidates,target,0,0,used);
        return res;
    }
};


http://www.kler.cn/a/155391.html

相关文章:

  • 阿里云通义大模型团队开源Qwen2.5-Coder:AI编程新纪元
  • 学法减分交管12123模拟练习小程序源码前端和后端和搭建教程
  • 陪诊问诊APP开发实战:基于互联网医院系统源码的搭建详解
  • AI制作ppt
  • 24.11.13 Javascript3
  • 6.2 对角化矩阵(2)
  • ROS报错:RLException:Invalid roslaunch XML Syntax: mismatched tag:
  • MFC 绘制单一颜色圆形、渐变颜色边框圆形、渐变填充圆形以及绘制三角函数正弦函数曲线.
  • 【web安全】CSRF漏洞攻击与防御
  • 从零开始:PHP实现阿里云直播的简单方法!
  • Java通过Redis进行延时队列,定时发布消息(根据用户选择时间进行发布)
  • python爬虫抓取网页图片教程
  • Spring事务管理介绍
  • yolo.txt格式与voc格式互转,超详细易上手
  • Centos图形化界面封装OpenStack Ubuntu镜像
  • Electron+Ts+Vue+Vite桌面应用系列:TypeScript常用时间处理工具
  • Python ctypes:揭秘高级Python与底层交互秘籍
  • JavaScript编程基础 – For循环
  • ChatGPT等大语言模型为什么没有智能
  • JavaWeb | 表单开发
  • 智能优化算法应用:基于原子搜索算法无线传感器网络(WSN)覆盖优化 - 附代码
  • 二叉树在线OJ
  • python-迭代器与生成器
  • 强化学习(一)——基本概念及DQN
  • matlab科学计算
  • 如何使用注解实现接口的幂等性校验