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

给定一个候选人编号的集合 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.mfbz.cn/a/200312.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux安装minIo(亲测可用)

一、创建文件夹 进入opt文件夹 cd /opt/创建minio文件夹&#xff1b; mkdir minio赋予权限 chmod 777 minio/执行完后查看目录 进到minio文件夹 创建bin目录 mkdir bin创建data目录 mkdir data创建log touch minio.log创建start.sh文件&#xff0c;并写入数据(不会vi或…

搞定这三个问题 伦敦金止损就没问题

笔者多次强调&#xff0c;做伦敦金交易&#xff0c;重要的是风险控制。而止损是我们风险控制中一个很重要的概念。设定好止损&#xff0c;就是风险控制的好开始。下面我们通过三个问题&#xff0c;来解决止损的问题。 问题一&#xff0c;你的止损位在哪里&#xff1f;要做止损&…

多目标水母搜索算法(MOJS)求解微电网优化MATLAB

一、微网系统运行优化模型 微电网优化模型介绍&#xff1a; 微电网多目标优化调度模型简介_IT猿手的博客-CSDN博客 二、多目标水母搜索算法MOJS 多目标水母搜索算法&#xff08;Multi-Objective Jellyfish Search algorithm&#xff0c;MOJS&#xff09;由Jui-Sheng Chou等…

软工2021上下午第六题(组合模式)

阅读下列说明和Java代码&#xff0c;将应填入&#xff08;n&#xff09;处的字句写在答题纸的对应栏内。 【说明】 层叠菜单是窗口风格的软件系统中经常采用的一种系统功能组织方式。层叠菜单中包含的可能是一个菜单项&#xff08;直接对应某个功能&#xff09;&#xff0c;也可…

three.js--立方体

使用three.js渲染出可以调节大小的立方体 1.搭建开发环境 1.首先新建文件夹用vsc打开项目终端 2.执行npm init -y 创建配置文件夹 3.执行npm i three0.152 安装three.js依赖 4.执行npm I vite -D 安装 Vite 作为开发依赖 5.根目录下新建index.html 作为页面入口文件 …

一文例说嵌入式 C 程序的内聚和耦合

1 - 原理篇 低耦合&#xff0c;是指模块之间尽可能的使其独立存在&#xff0c;模块之间不产生联系不可能&#xff0c;但模块与模块之间的接口应该尽量少而简单。这样&#xff0c;高内聚从整个程序中每一个模块的内部特征角度&#xff0c;低耦合从程序中各个模块之间的关联关系…

Java基于springboot开发的土特产网站商城多商家源码

主要功能&#xff1a;用户可以浏览特产&#xff0c;按分类和产地搜索&#xff0c;按分类查询特产&#xff0c;搜索店铺&#xff0c;查看评价&#xff0c;加入购物车&#xff0c;下单&#xff0c;查看店铺主页信息特产等店铺内搜索等&#xff1b;用户可申请开通店铺&#xff0c;…

AI伪原创软件-AI伪原创工具下载

在当今数字化时代&#xff0c;创作者们在追求独特创意的同时&#xff0c;也面临着时间和灵感的双重挑战。AI伪原创技术应运而生&#xff0c;为创作者提供了一种快捷而便利的解决方案。本文将专心分享两款备受瞩目的AI伪原创工具&#xff0c;147SEO伪原创、百度文心一言伪原创&a…

夸克大模型助力学术科研提效 四大优势提升知识正确性

当严谨的学术科研与创新的大模型技术结合在一起&#xff0c;会擦出什么样的火花&#xff1f;日前&#xff0c;夸克大模型甫一推出便以优秀的性能成为国产大模型中的“学霸”。在中国科学技术协会近期主办的“大模型应用场景研讨会”上&#xff0c;夸克大模型在快速阅读、创作润…

java开发之个微群聊管理

简要描述&#xff1a; 群管理操作 请求URL&#xff1a; http://域名/operateChatRoom 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明w…

DCGAN 使用指南:将卷积神经网络和对抗网络结合,适用于生成小尺寸的图像

DCGAN 使用指南&#xff1a;将卷积神经网络和对抗网络结合 网络结构细节设计 论文地址&#xff1a;https://arxiv.org/abs/1511.06434 项目代码&#xff1a;https://github.com/tensorlayer/DCGAN.git DCGAN 适用于生成小尺寸的图像&#xff0c;并且具有简单易用的优势 Styl…

初中古诗文大会填空题的常见题型和阅读专辑的对应知识点分析

前面两篇文章&#xff0c;六分成长为您介绍了2023年初中古诗文大会复选&#xff08;复赛&#xff09;单选题和多选题的常见题型和考察点&#xff0c;并且从历年真题和中学生古诗文阅读专辑&#xff08;初中适用&#xff0c;下称《专辑》&#xff09;中各选了一些题目作为示例&a…

龙芯loongarch64服务器编译安装maturin

前言 maturin 是一个构建和发布基于 Rust 的 Python 包的工具,但是在安装maturin的时候,会出现如下报错:error: cant find Rust compiler 这里记录问题解决过程中遇到的问题: 1、根据错误的提示需要安装Rust Compiler,首先去其官网按照官网给的解决办法提供进行安装 curl…

C语言进阶指南(11)(指针数组与二维数组)

*欢迎来到博主的专栏——C语言进阶指南 博主id&#xff1a;reverie_ly 文章目录 N级指针指针数组指针数组与二维数组数组指针作为函数的参数 N级指针 指针变量是一个存放地址的变量&#xff0c;在C语言中&#xff0c;每个变量都会有一个地址值。所以指针变量也有一个地址。 …

算法—双指针

双指针算法可以帮忙把时间复杂度降低一个维度&#xff0c;即原本O&#xff08;n2&#xff09;降为O(n)&#xff1b;将O(n)降为O(1) 移动零 移动零 题目解析 将所有0移动到末尾保持非0元素相对顺序对数组进行原地操作&#xff08;不开辟额外空间&#xff09; 算法原理 数组…

互联网洗鞋店小程序怎么做,流程有哪些?

洗鞋店小程序让洗鞋更便捷高效&#xff0c;用户只需通过手机预约&#xff0c;即可享受上门取送服务&#xff0c;省时省力&#xff0c;让鞋子焕然一新。下面我们详细介绍这个小程序的功能&#xff1a; 1. 轻松预约&#xff1a;用户可以随时随地通过洗鞋店小程序预约洗鞋服务&…

SDN、SD-WAN、CDN、SDH分别是什么,有什么关联?

SDN代表“软件定义网络”&#xff0c;是一种网络架构&#xff0c;它将网络控制和数据转发分离。SDWAN代表“软件定义广域网”&#xff0c;是SDN的一种实现&#xff0c;在广域网中使用虚拟化技术来连接分支机构和数据中心。 CDN代表“内容分发网络”&#xff0c;是一种通过在全球…

Spring框架体系及Spring IOC思想

目录 Spring简介Spring体系结构SpringIOC控制反转思想自定义对象容器Spring实现IOCSpring容器类型容器接口容器实现类对象的创建方式使用构造方法使用工厂类的方法使用工厂类的静态方法对象的创建策略对象的销毁时机生命周期方法获取Bean对象的方式通过id/name获取通过类型获取…

GitHub----使用记录

一、上传文件到仓库 1、首先新建一个github仓库 然后先记住这一句指令 2、下载git工具 https://git-scm.com/downloads 下载工具安装不用运行 3、使用git工具上传文件并推送 找到你想上传的文件的位置&#xff0c;右击git Bush here git init &#xff1a;初始化这个仓…

CSP认证2023-03:田地丈量、垦田计划、LDAP,python满分解答代码

CSP认证2023-03&#xff1a;田地丈量、垦田计划、LDAP&#xff0c;python满分解答代码 目录 一、田地丈量 问题描述 输入输出 思路 代码和结果 二、垦田计划 问题描述 输入和输出 思路 代码和结果 三、LDAP 问题描述 思路 代码和结果 一、田地丈量 问题描…
最新文章