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

代码随想录DAY23 - 回溯算法 - 08/22

组合总和

题干

题目:给你一个 无重复元素整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

说明:

  • 2 <= candidates[i] <= 40,数组中都是正数

  • 解集不能包含重复的组合

链接:. - 力扣(LeetCode)

思路和代码

同样是组合,但这道题不限制组合的大小,也不限制同一数字的使用次数。之前在做组合题目时,每用一个数字,下一个组合就不能用之前用过的,但在这道题里,每考虑一个新组合时本身这个数字能再次使用,这就是在原组合题目的基础上要修改的地方。

递归法
  • 递归参数和返回值:参数是目标和 target、组合之和 sum、传入的集合 candidates、起始的元素位置 startIndex;无返回值。

  • 递归结束的条件:当组合之和 sum 大于等于 目标和target时就要返回。

  • 递归顺序:先确定组合中的一个元素,再递归寻找下一个元素凑组合。但和之前不同的是,我们递归寻找下一个元素时还可以是自身,因为可以重复,因为递归时候传入的起始位置仍为 i,即 backTracking(target, sum, candidates, i),而不是 i+1。

class Solution {
public:vector<int> composition; // 记录组合vector<vector<int>> result; // 记录所有组合的结果void backTracking(int target, int &sum, vector<int>& candidates, int startIndex){if (sum == target){ // sum 记录组合之和result.push_back(composition);return;} else if (sum > target){return;}for (int i = startIndex; i < candidates.size(); ++i) {int num = candidates[i];composition.push_back(num);sum += num;backTracking(target,sum,candidates,i); // 这里输入应该是 i,而不是 i+1,因为元素可以重复composition.pop_back();sum -= num;}}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {int sum = 0;backTracking(target,sum,candidates,0);return result;}
};
递归优化:剪枝

优化:对数组排序并减少不必要的 for 循环

数组 candidates 本身是无序的,因此我们在遍历到 sum > target 时返回后,又需要继续遍历下一个元素。但如果数组是升序排列,当 sum > target 时,也不需要往下再遍历了,因为之后的数组元素只会更大,不可能再出现 sum = target 的情况,可以直接终止循环。

class Solution {
public:vector<int> composition;vector<vector<int>> result;void backTracking(int target, int &sum, vector<int>& candidates, int startIndex){if (sum == target){result.push_back(composition);return;}for (int i = startIndex; i < candidates.size() && sum+candidates[i] <= target; ++i) {// 剪枝操作,如果加入当前元素已经 > target 直接终止循环int num = candidates[i];composition.push_back(num);sum += num;backTracking(target,sum,candidates,i); composition.pop_back();sum -= num;}}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {int sum = 0;sort(candidates.begin(),candidates.end()); // 升序排列backTracking(target,sum,candidates,0);return result;}
};

组合总和Ⅱ

题干

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

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

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

说明:

  • 1 <= candidates[i] <= 50,数组中只有正数

  • 数组中可能有重复元素

链接:. - 力扣(LeetCode)

思路和代码

本题和上一题不一样的地方就在于数组 candidates 中可能包含重复的数字,而且每个数字在一次组合中只能使用一次,不可以多次使用。由于有重复的数字,这样递归求得的组合中可能会重复,因此我们需要先对 candidates 去重,重复出现的数字其实表明了该数字在组合中可以用多少次,我们需要记录下不同数字的使用次数。

递归法
class Solution {
public:int count[51]; // 记录不同数字的使用次数, 1 <= candidates[i] <= 50vector<int> composition; // 记录组合vector<vector<int>> result; // 记录所有组合的结果void backTracking(vector<int>& candidates, int target, int sum, int startIndex){if (sum == target){result.push_back(composition);return;} else if (sum > target){return;}for (int i = startIndex; i < candidates.size(); ++i) {int num = candidates[i];sum += num;composition.push_back(num);count[num]--; // 此时数字 num 已被使用一次,故次数减一if (count[num] > 0) backTracking(candidates,target,sum,i); // 若还有使用次数,则重复使用数字else backTracking(candidates,target,sum,i+1); // 若没有使用次数,则使用下一个数字composition.pop_back();sum -= num;count[num]++;}}vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {vector<int> newCandidates; // 记录去重后的新数组for (int i : candidates) {if (count[i] == 0){newCandidates.push_back(i);}count[i]++; // 记录下每个数字的使用次数}backTracking(newCandidates,target,0,0);return result;}
};
递归优化:剪枝

同样是对 candidates 数组进行升序排序,这样当 sum > target 时无需再进入循环。

class Solution {
public:int count[51]; // 1 <= candidates[i] <= 50vector<int> composition;vector<vector<int>> result;void backTracking(vector<int>& candidates, int target, int sum, int startIndex){if (sum == target){result.push_back(composition);return;}for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ++i) {// 剪枝,减少循环int num = candidates[i];sum += num;composition.push_back(num);count[num]--;if (count[num] > 0) backTracking(candidates,target,sum,i);else backTracking(candidates,target,sum,i+1);composition.pop_back();sum -= num;count[num]++;}}vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {vector<int> newCandidates; // 记录去重后的新数组for (int i : candidates) {if (count[i] == 0){newCandidates.push_back(i);}count[i]++; // 记录下每个数字的使用次数}sort(newCandidates.begin(),newCandidates.end()); // 排序backTracking(newCandidates,target,0,0);return result;}
};

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Axure RP 9高手速成秘籍:解锁终极快捷键,设计效率飙升10倍!
  • Unity动画模块 之 3D模型导入基础设置 Rig页签
  • 51单片机-LED灯蜂鸣器数码管按键DS18B20温度传感器
  • git 指令
  • [数据集][目标检测]电力场景轭式悬架锈蚀分类数据集6351张2类别
  • 鸿蒙卡片服务开发
  • linux容器基础-namespace-3(pid)
  • 学习记录——day34 IO多路复用 fcntl select poll select实现聊天室
  • C#工具库-NPOI
  • 案例分享—优秀国外界面设计配色舒适的原因
  • Kubernetes--深入Pod
  • MySQL索引失效的场景
  • Linux~系统基础学习
  • 深入探讨SD NAND的SD模式与SPI模式初始化
  • [数据集][目标检测]agvs仓储机器人检测数据集VOC+YOLO格式967张3类别
  • hexo+github搭建个人博客
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • Android优雅地处理按钮重复点击
  • E-HPC支持多队列管理和自动伸缩
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • Promise面试题2实现异步串行执行
  • React Native移动开发实战-3-实现页面间的数据传递
  • React-redux的原理以及使用
  • Service Worker
  • SOFAMosn配置模型
  • 阿里研究院入选中国企业智库系统影响力榜
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 使用API自动生成工具优化前端工作流
  • 微服务核心架构梳理
  • 用mpvue开发微信小程序
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • #70结构体案例1(导师,学生,成绩)
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • (3)nginx 配置(nginx.conf)
  • (7)STL算法之交换赋值
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (CVPRW,2024)可学习的提示:遥感领域小样本语义分割
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (动态规划)5. 最长回文子串 java解决
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (亲测有效)推荐2024最新的免费漫画软件app,无广告,聚合全网资源!
  • (三) diretfbrc详解
  • (三)uboot源码分析
  • (十)c52学习之旅-定时器实验
  • (一) springboot详细介绍
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (自用)网络编程
  • .bat批处理(三):变量声明、设置、拼接、截取