leetCode 40.组合总和 II + 回溯算法 + 剪枝 + used数组 + 图解

news2024/11/27 13:42:23

给定一个候选人编号的集合 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]
]

(一)解法一:used数组

思路和分析:本题和这道题的 leetCode 39.组合总和 + 回溯算法 + 剪枝 的区别是:

  • 不同点
  1. 本题candidates 中的每个数字在每个组合中只能使用 一次 
  2. 本题数组candidates 的元素是有重复的,而 leetCode 39. 无重复元素的数组candidates
  • 相同点
  1. 解集不能包含重复的组合

总结此题要求:元素在同一个组合内是可以重复的,多少次都可以,但两个组合不能相同。换句话说:集合(数组candidates)有重复元素,但还不能有重复的组合 

举个栗子:candidates = [1, 1, 2], target = 3 (注意前提candidates 已经排序了)

思考(O_O)?为啥used[i-1] == false能表示同一树层candidates[i-1] “使用过” 这种情况呢?

  • 是因为在同一树层used[i-1] == false 能表示当前取的candidates[i]是从candidates[i-1]回溯而来的
  • used[i]==true,表示进入下一层递归,取下一个数,所以在树枝上

 >>问题思考(O_O)?

1).什么是“去重”

  • “去重”:就是使用过的元素不能重复选取

2).何为“树枝去重”“树层去重”(代码随想录Carl老师自创的名词)

可把组合问题抽象为树形结构,used“使用过”)在这个树形结构上是有两个维度的,一个维度表示是同一树枝上使用过,一个维度表示是同一树层上使用过

来看题目要求:“集合(数组candidates重复元素,但还不能有重复的组合 ”。

去重的是同一树层上的“使用过”是不同组合里的元素,而对于同一树枝上的都是一个组合里的元素,不用去重。 

  • 强调注意:在树层去重时,需要对数组排序

>>回溯三部曲:

1).确定回溯函数参数

  • path来收集符合条件的结果
  • result 保存 path,作为结果集
  • startIndex 来控制for循环的起始位置
  • used 是bool型数组,用来记录同一树枝上的元素是否使用过
vector<vector<int>> result;
vector<int>path;
void backtracking(vector<int>& candidates,int sum,int target,vector<bool>&used,int startIndex) 

2).递归的终止条件

  • sum > target 和 sum == targe
if (sum > target) { // 这个条件其实可以省略
    return;
}
if (sum == target) {
    result.push_back(path);
    return;
}

================================================================================
可以写成这样:
在递归单层遍历的时候,会有剪枝的操作
for(int i=startIndex;i<candidates.size() && sum + candidates[i] <= target;i++) {
    ...
}

在这篇文章中有提到 for循环剪枝操作sum + candidates[i] <= target为「剪枝操作」。感兴趣的小伙伴们可以看一下:leetCode 39.组合总和 + 回溯算法 + 剪枝 icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/134672946?spm=1001.2014.3001.5501

3).单层搜索的逻辑

if( i>0 && candidates[i] == candidates[i - 1] && used[i - 1] == false),表示前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]。那么此时 for循环 里通过 continue 操作跳过此种情况的递归

for(int i=startIndex;i<candidates.size() && sum + candidates[i] <= target;i++) {

    if(i>0 && candidates[i]==candidates[i-1] && used[i-1]==false) continue;

    ......
}

C++代码:

class Solution {
public:
    vector<vector<int>> result;
    vector<int>path;
    void backtracking(vector<int>& candidates,int sum,int target,vector<bool>&used,int startIndex) {
        if(sum == target) {
            result.push_back(path);
            return;
        }
        for(int i=startIndex;i<candidates.size() && sum + candidates[i] <= target;i++) {
            /*
                used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
                used[i - 1] == false,说明同一树层candidates[i - 1]使用过
                要对同一树层使用过的元素进行跳过
            */
            if(i>0 && candidates[i]==candidates[i-1] && used[i-1]==false) continue;
            path.push_back(candidates[i]);
            sum+=candidates[i];
            used[i]=true;
            backtracking(candidates,sum,target,used,i+1);// 和39.组合总和的区别1,这里是i+1,每个数字在每个组合中只能使用一次
            used[i]=false;
            sum-=candidates[i];
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<bool> used(candidates.size(), false);
        // 首先把给candidates排序,让其相同的元素都挨在一起。
        sort(candidates.begin(),candidates.end());  
        backtracking(candidates,0,target,used,0);
        return result;
    }
};

(二)解法二:不用 used 数组,而用 startIndex 来去重

class Solution {
public:
    vector<vector<int>> result;
    vector<int>path;
    void backtracking(vector<int>& candidates,int sum,int target,int startIndex) {
        if(sum == target) {
            result.push_back(path);
            return;
        }
        for(int i=startIndex;i<candidates.size() && sum + candidates[i] <= target;i++) {
            if(i>startIndex && candidates[i]==candidates[i-1]) continue;
            path.push_back(candidates[i]);
            sum+=candidates[i];
            backtracking(candidates,sum,target,i+1);// 和39.组合总和的区别1,这里是i+1,每个数字在每个组合中只能使用一次
            sum-=candidates[i];
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<bool> used(candidates.size(), false);
        // 首先把给candidates排序,让其相同的元素都挨在一起。
        sort(candidates.begin(),candidates.end());  
        backtracking(candidates,0,target,0);
        return result;
    }
};

参考文章和推荐视频:

代码随想录 (programmercarl.com)icon-default.png?t=N7T8https://www.programmercarl.com/0040.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CII.html#%E6%80%9D%E8%B7%AF回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV12V4y1V73A/?p=66&spm_id_from=pageDriver&vd_source=a934d7fc6f47698a29dac90a922ba5a3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1267043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库应用-H2database--未授权访问命令执行漏洞

数据库应用-H2database–未授权访问&命令执行漏洞 Java SQL 数据库 H2,H2的主要特点是&#xff1a;非常快&#xff0c;开源&#xff0c;JDBC API&#xff1b;嵌入式和服务器模式&#xff1b;内存数据库&#xff1b;基于浏览器的控制台应用程序。 H2 数据库控制台中的另一…

依靠堡塔面板,飞速部署Java项目

依靠堡塔面板&#xff0c;飞速部署Java项目 环境介绍 环境介绍&#xff1a; 面板版本&#xff1a;8.0.26 操作系统版本&#xff1a;CentOS7.9.2009 Nginx版本&#xff1a;1.22 Java环境&#xff1a;Tomcat8&#xff0c;JDK&#xff1a;OpenJDK-1.8.0-internal MySQL版本&#…

028 - STM32学习笔记 - ADC(二) 独立模式单通道中断采集

028 - STM32学习笔记 - 结构体学习&#xff08;二&#xff09; 上节对ADC基础知识进行了学习&#xff0c;这节在了解一下ADC相关的结构体。 一、ADC初始化结构体 在标准库函数中基本上对于外设都有一个初始化结构体xx_InitTypeDef&#xff08;其中xx为外设名&#xff0c;例如…

数字时代的表演艺术:TikTok如何重新定义舞台

在数字时代的潮流中&#xff0c;TikTok崭露头角&#xff0c;重新定义了表演艺术的舞台。这款短视频应用不仅改变了用户与内容的互动方式&#xff0c;也为艺术家和创作者提供了全新的表达平台。本文将深入探讨TikTok如何在数字时代重新定义舞台&#xff0c;以及它对表演艺术的深…

《围城》思维导图

《围城》是一幅栩栩如生的市井百态图&#xff0c;人生的酸甜苦辣千般滋味均在其中得到了淋漓尽致的体现。钱钟书先生将自己的语言天才并入极其渊博的知识&#xff0c;再添加上一些讽刺主义的幽默调料&#xff0c;以一书而定江山。《围城》显示给我们一个真正的聪明人是怎样看人…

Nginx热部署

快捷查看指令 ctrlf 进行搜索会直接定位到需要的知识点和命令讲解&#xff08;如有不正确的地方欢迎各位小伙伴在评论区提意见&#xff0c;小编会及时修改&#xff09; Nginx热部署 首先来讲一下为什么要进行热部署 nginx 支持热加载 热部署 &#xff0c;在不打断用户请求的情…

什么是高层设计 - 学习系统设计

高层设计或HLD指的是整体系统设计&#xff0c;包括系统架构和设计的描述&#xff0c;是一种通用的系统设计&#xff0c;包括&#xff1a; •系统架构•数据库设计•对系统、服务、平台和模块之间关系的简要描述。 高层设计或HLD也被称为宏观级别设计。 什么是高层设计文档&…

中国信通院发布《中国算力发展指数白皮书》(2023)

加gzh“大数据食铁兽”&#xff0c;回复“20231129”&#xff0c;获取材料完整版 导读 2023 年白皮书在 2022 年的基础上&#xff0c;加强了全球和我国算力发展的研究&#xff0c;客观评估我国整体、各省份及各城市现阶段的算力发展水平进一步给出我国算力二十强市榜单&…

什么是线程安全问题?如何确保线程安全?进来看看就明白了!!

&#x1f308;&#x1f308;&#x1f308;今天给大家分享的是:什么是线程安全&#xff0c;在程序中多线程并发执行的时候&#xff0c;是否会产生线程不安全问题&#xff0c;以及如何解决线程不安全问题。 清风的CSDN博客 &#x1f6e9;️&#x1f6e9;️&#x1f6e9;️希望我的…

小红书广告投放形式有哪些,软文形式特点是什么?

现在广告的形式多种多样&#xff0c;针对不同的投放形式&#xff0c;面对的用户群体和投放渠道也都不一样。在平台上进行广告投放&#xff0c;可以快速提升品牌曝光和销量转化。本次将围绕小红书广告投放形式有哪些&#xff0c;软文形式特点是什么展开讨论&#xff0c;希望能对…

今日份推荐、无广告、超实用的5款软件

​ 大家好&#xff0c;我又来啦&#xff0c;今天给大家带来的几款软件&#xff0c;共同特点都是无广告、超实用&#xff0c;大家观看完可以自行搜索下载哦。 1.键盘锁定工具——Iwck ​ Iwck是一款简单实用的键盘锁定工具&#xff0c;可以让你在需要的时候暂时停止键盘的所有…

【23真题】官方出错题,复试不算分!信号学不好,就考它!

今天分享的是23年广西民族大学861的信号与系统试题及解析。广西民族我之前做择校分析的时候说过&#xff0c;考生进入复试之后&#xff0c;专业课会扣掉&#xff01;不算分&#xff0c;只对公共课排名&#xff01;而且专业课简单&#xff0c;但是官方今年出了好几道错题&#x…

陪诊系统:基于自然语言处理的患者沟通创新

医疗领域的数字化转型正日益引入创新技术&#xff0c;其中基于自然语言处理&#xff08;NLP&#xff09;的陪诊系统成为提升患者沟通的一项关键技术。本文将深入研究这一领域&#xff0c;介绍陪诊系统如何借助NLP实现患者沟通的创新&#xff0c;并提供一个简单的Python代码示例…

CNAS认可是什么?CNAS软件测试报告如何获取?

一、CNAS认可是什么?   CNAS认可是指中国合格评定国家认可委员会的认可程序。CNAS是中国最高级别的认可机构&#xff0c;负责审核和认可符合国家标准的实验室、检测机构和认证机构。通过CNAS认可&#xff0c;机构可以获得国际公认的认可证书&#xff0c;证明其测试结果和认证…

【华为数通HCIP | 网络工程师】821刷题日记-BFD和VRRP 及重点(1)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

人工智能_机器学习055_拉格朗日乘子法_拉格朗日乘数法的原理介绍_流程详解---人工智能工作笔记0095

上一节我们已经演示了把SVM支持向量机的分割线,画出来,并且,我们也推导了SVM支持向量机的公式,但是支持向量机的公式,是带有条件的对吧,带有条件就算起来比较麻烦 可以看到现在我们要可以用,拉格朗日乘数法,将 有等式约束条件的优化问题 转换为 无约束优化问题,把有条件转换为…

Vue diff 算法探秘:如何实现快速渲染

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

During handling of the above exception, another exception occurred解决方案

During handling of the above exception, another exception occurred解决方案 前言解决方案总结 前言 今天在写python读取图片中的内容的脚本的时候&#xff0c;常用的图像处理库包括Pillow和OpenCV。以下是使用Pillow库读取图片中的计算公式的示例代码&#xff1a; from P…

cocos creator-碰撞检测

碰撞检测文档 刚体自行选择&#xff0c;刚体正常设置分组、tag&#xff0c;tag用于区分是哪个物体被碰撞了 正常在一个node下挂载脚本就行 注意&#xff1a;Builtin 2D 物理模块只会发送 BEGIN_CONTACT 和 END_CONTACT 回调消息。ccclass(TestContactCallBack) export class …

C语言--根据成绩判断等级

一.题目描述 如果学生的成绩小于60分&#xff0c;那么输出不及格 如果学生的成绩大于60分小于85分&#xff0c;那么输出良好 如果学生的成绩大于85分&#xff0c;那么输出优秀 二.代码实现 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> //根据成绩打印等级 //scor…