代码随想录-回溯(组合问题)|ACM模式

目录

前言:

77.组合

题目描述:

输入输出示例:

思路和想法:

216. 组合总和 III

题目描述:

输入输出示例:

思路和想法:

17. 电话号码的字母组合

题目描述:

输入输出描述:

思路和想法:

40. 组合总和 II

题目描述:

输入输出描述:

思路和想法:


前言:

这里对于组合问题,进行了深入的探讨(ACM模式):

  • 数组集合里元素不重复,元素只能取一次,组合不许重复
  • 引入总和统计
  • 引入map哈希
  • 引入去重的概念---(数组集合里元素有重复,元素只能取一次,但组合不许重复)

77.组合

题目描述:

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

输入输出示例:

示例1:

输入:n = 4,k = 2 输出:[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]

示例2:

输入:n = 1,k = 1 输出:[[1]]

提示:

  • 1 <= n <= 20
  • 1 <= k <= n

思路和想法:

回溯法的问题,都可以抽象为树形结构问题。

回溯法解决的是在集合中递归查找子集,集合的大小构成树的宽度,递归的深度构成树的深度。

这道题目属于组合问题的模板题。

#include <bits/stdc++.h>using namespace std;
/*
* 作者:希希雾里
* 77.组合
* *//*
* 这里我们能够比较清晰的,要使用回溯。
* */
vector<vector<int>> result;
vector<int> path;
//这里对于回溯要传入的参数:元素数量,限定条件以及要开始遍历的元素
//这里能够比较清晰的知道n即为回溯的宽度,k即为回溯的深度。
void backtracing(int n, int k, int startIndex){/*终止条件*/if(path.size() == k){result.push_back(path);return;}/*处理节点 + 回溯撤销*/for (int i = startIndex; i <= n; ++i) {path.push_back(i);backtracing(n, k, i+1);path.pop_back();}
};int main() {int n, k;cin>> n >> k;result.clear();path.clear();backtracing(n, k,1);//结果输出for (int i = 0; i < result.size(); ++i) {for (int j = 0; j < result[i].size(); ++j) {cout << result[i][j];if(j != result[i].size() - 1) cout << " ";}//注意最后输出不需要换行。if(i == result.size() - 1) return 0;cout << endl;}return 0;
}/*  测试样例
4 21 1
*
* */

216. 组合总和 III

题目描述:

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

输入输出示例:

示例1:

输入:k = 3, n = 7 输出:[[1,2,4]]

示例2:

输入:k = 3, n = 9 输出:[[1,2,6], [1,3,5], [2,3,4]]

示例3:

输入: k = 4, n = 1 输出:[]

提示:

  • 2 <= k <= 9
  • 1 <= n <= 60

思路和想法:

这道题目和上一道题基本一致,在原有基础上,还需要统计path里元素的总和,终止条件发生了改变, path.size() == k && sum == n 。

#include <bits/stdc++.h>using namespace std;
/*
* 作者:希希雾里
* 216.组合总和III
* */
vector<vector<int>> result;
vector<int> path;
int sum = 0;
//这里对于回溯要传入的参数,集合个数,目标总和以及要遍历的元素下标
void backtracing(int k, int n, int startIndex){/*终止条件*/if(path.size() == k && sum == n){result.push_back(path);return;}/*处理节点 + 回溯撤销*/for (int i = startIndex; i <= 9; ++i) {path.push_back(i);sum += i;backtracing(n, k, i + 1);sum -= path.back();path.pop_back();}
};int main() {int n, k;cin>> n >> k;result.clear();path.clear();backtracing(k, n,1);//结果输出for (int i = 0; i < result.size(); ++i) {for (int j = 0; j < result[i].size(); ++j) {cout << result[i][j];if(j != result[i].size() - 1) cout << " ";}//注意最后输出不需要换行。if(i == result.size() - 1) return 0;cout << endl;}return 0;
}

17. 电话号码的字母组合

题目描述:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

输入输出描述:

示例1:

输入:digits = "23" 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例2:

输入:digits = "" 输出:[]

示例3:

输入:digits = "2" 输出:["a","b","c"]

提示:

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字

思路和想法:

这里首先构建数字和字符之间的映射,后续就是组合问题,采用回溯方法就可以解决了。

#include <bits/stdc++.h>using namespace std;
/*
* 作者:希希雾里
* 17.电话号码的字母组合
* */
vector<string> result;
string s;
//构建map,建立映射
const string map_letter[10] = {
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz",
};/*
* 函数:          backtracing()
* 输入参数:       digits:输入的字符串    index:字符串元素下标 
* */
void backtracing(const string & digits, int index){/*终止条件*/if(index == digits.length()){result.push_back(s);return;}int digit = digits[index] - '0';string letters = map_letter[digit];/*处理节点 + 回溯过程*/for (int i = 0; i < letters.length(); ++i) {s.push_back(letters[i]);backtracing(digits, index + 1);s.pop_back();}
};int main() {result.clear();s.clear();//字符串输入string str;getline(cin,str);backtracing(str, 0);//结果输出for (int i = 0; i < result.size(); ++i) {//注意最后输出不需要换行。cout << result[i];if(i == result.size() - 1) return 0;cout << endl;}return 0;
}/*  测试样例
232
*
* */

40. 组合总和 II

题目描述:

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

思路和想法:

这道题目和之前不一样的地方在于,要取的数组里有数值相等的元素并且要求解集不能包含重复的组合。所以这道题目涉及到了去重。

一个组合里可以有重复的元素,即不需要树枝去重(纵向)。不能有重复的组合,即要进行树层去重(横向)。

树层去重和树枝去重,是根据树形结构,提出的去重概念。

那么转换到具体实现上,需要解决两个问题:

  • 如何实现去重?这里先对数组进行排序,将重复的元素紧挨在一起,之后遍历时判断与前面的元素是否相等即可。
  • 如何分辨树层去重和树枝去重?这里采用一个bool数组used,used[i - 1] == true,说明同一树枝candidates[i - 1]使用过,used[i - 1] == false,说明同一树层candidates[i - 1]使用过。
#include <bits/stdc++.h>using namespace std;
/*
* 作者:希希雾里
* 40. 组合总和 II
* */
vector<vector<int>> result;
vector<int> path;
int sum = 0;/*
* 函数:          backtracing()
* 输入参数:       candidates:输入的数组    target: 目标数值     index:字符串元素下标       used:标志数组
* */
void backtracing(vector<int>& candidates, int target, int index, vector<bool>& used){if(sum == target){result.push_back(path);return;}for(int i = index; i < candidates.size();++i){if(i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false){continue;}path.push_back(candidates[i]);sum += candidates[i];used[i] = true;backtracing(candidates, target, i + 1, used);used[i] = false;sum -= candidates[i];path.pop_back();}
};int main() {result.clear();path.clear();vector<int> candidates;int n;while(cin >> n){candidates.push_back(n);if(getchar() == '\n'){break;}}int target;cin >> target;vector<bool> used(candidates.size(),false);//默认升序排序sort(candidates.begin(),candidates.end());backtracing(candidates, target, 0, used);//结果输出for (int i = 0; i < result.size(); ++i) {for (int j = 0; j < result[i].size(); ++j) {cout << result[i][j];if(j != result[i].size() - 1) cout << " ";}//注意最后输出不需要换行。if(i == result.size() - 1) return 0;cout << endl;}return 0;
}/*  测试样例
10 1 2 7 6 1 5
82 5 2 1 2
5
*
* */

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

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

相关文章

MyBatis的多表操作

1 MyBatis的多表操作 1.1 多表模型介绍 我们之前学习的都是基于单表操作的&#xff0c;而实际开发中&#xff0c;随着业务难度的加深&#xff0c;肯定需要多表操作的。 多表模型分类 一对一&#xff1a;在任意一方建立外键&#xff0c;关联对方的主键。 一对多&#xff1a;在…

实用便捷!一站式BI系统推荐

在企业数字化转型过程中&#xff0c;BI系统可以建立业务、数据的双驱引擎&#xff0c;形成业务、数据的互补作用&#xff0c;通过建立数字化技术架构&#xff0c;明确企业的战略定位和业务目标&#xff0c;从而支撑实现这个目标。而一站式BI系统&#xff0c;则是指可以轻松从数…

【MySQL】SQL性能分析 (七)

&#x1f697;MySQL学习第七站~ &#x1f6a9;本文已收录至专栏&#xff1a;MySQL通关路 ❤️文末附全文思维导图&#xff0c;感谢各位点赞收藏支持~ 假如我们需要对SQL进行优化&#xff0c;我们就必须对他足够的了解&#xff0c;比如 对哪一类SQL进行优化&#xff08;增删改查…

基于物联网网关的工业数据可视化平台有什么功能?

随着数字化浪潮的不断发展&#xff0c;工业数据的价值越来越重要。在企业利用数据的过程中&#xff0c;数据可视化是数字化系统中十分重要的一部分。然而&#xff0c;工厂多种设备、多种协议影响到系统的搭建使得企业无法获得全面的数据视图&#xff0c;也无法对整个生产流程进…

OJ练习第142题——路径总和 II

113. 路径总和 II 力扣链接&#xff1a;113. 路径总和 II 题目描述 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 Java代码&#xff08;深度优先搜…

六边形架构

六边形架构 微服务系统架构微服务定义微服务系统设计 传统分层架构六边形架构参考资料 微服务系统架构 需求描述做什么的问题&#xff0c;架构描述怎么做的问题(描述组成系统的各部件及其之间的关系) 微服务定义 下面的定义来自周志明老师的 凤凰架构 微服务是一种通过多个小型…

【Linux】 由“进程”过渡到“线程” -- 什么是线程(thread)?

知识引入初识线程1.什么叫做进程&#xff1f;2.什么叫做线程&#xff1f;3.如何看待我们之前学习的进程&#xff1f; 理解线程创建线程函数调用1.线程一旦被创建&#xff0c;几乎所有资源都是被线程所共享的2.与进程之间切换相比&#xff0c;线程的切换 初识线程总结&#xff1…

使用 Docker 快速上手中文版 LLaMA2 开源大模型

本篇文章&#xff0c;我们聊聊如何使用 Docker 容器快速上手朋友团队出品的中文版 LLaMA2 开源大模型&#xff0c;国内第一个真正开源&#xff0c;可以运行、下载、私有部署&#xff0c;并且支持商业使用。 写在前面 感慨于昨天 Meta LLaMA2 模型开放下载之后&#xff0c;Git…

操作系统练习:进程间通信(共享内存方式)

说明 本文是《操作系统概念(第九版)》3.4节“进程间通信”的练习。 进程间通信主要由两种模型&#xff1a; 共享内存消息传递 本文使用共享内存的方式实现进程间的通信 创建消息生产者 创建生产者的主要操作包括&#xff1a; 定义共享内存的大小、名称&#xff0c;以及通…

netty知识集锦2

粘包半包 粘包半包解决方案&#xff0c; 1短链接&#xff0c;它的消息边界是从链接建立到链接断开 2.定长解码器&#xff1a;服务器端选最大长度的消息作为定长&#xff0c;客户端不足补齐&#xff0c;缺点造成浪费 netty协议设计与解析 Message编码解码

AWS IAM介绍

前言 AWS是世界上最大的云服务提供商&#xff0c;它提供了很多组件供消费者使用&#xff0c;其中进行访问控制的组件叫做IAM(Identity and Access Management)&#xff0c; 用来进行身份验证和对AWS资源的访问控制。 功能 IAM的功能总结来看&#xff0c;主要分两种&#xff1…

《零基础入门学习Python》第060讲:论一只爬虫的自我修养8:正则表达式4

有了前面几节课的准备&#xff0c;我们这一次终于可以真刀真枪的干一场大的了&#xff0c;但是呢&#xff0c;在进行实战之前&#xff0c;我们还要讲讲正则表达式的实用方法和扩展语法&#xff0c;然后再来实战&#xff0c;大家多把持一会啊。 我们先来翻一下文档&#xff1a;…

openGauss学习笔记-17 openGauss 简单数据管理-表达式

文章目录 openGauss学习笔记-17 openGauss 简单数据管理-表达式17.1 简单表达式17.2 条件表达式17.3 子查询表达式17.4 数组表达式17.5 行表达式 openGauss学习笔记-17 openGauss 简单数据管理-表达式 表达式类似一个公式&#xff0c;我们可以将其应用在查询语句中&#xff0c…

25 MFC 数据库

文章目录 导入ADO库 导入ADO库 #import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","rsEOF")void CADODlg::OnBnClickedBtnQuery() {//导入ADO库::CoInitialize(NULL);//初始化COM库_ConnectionPtr pCo…

《面试1v1》如何提高远程用户的吞吐量

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…

Flutter动画库:animations(路由过渡动画或者页面切换动画)

animations animations 是一个 Flutter 库&#xff0c;它提供了一组用于创建动画效果的工具和组件。这个库的核心重点是路由过渡动画或者页面切换动画 地址 https://pub-web.flutter-io.cn/packages/animations 安装 flutter pub add animations看了下官方文档和官方例子&a…

计科web常见错误排错【HTTP状态404、导航栏无法点开、字符乱码及前后端数据传输呈现、jsp填写的数据传到数据库显示null、HTTP状态500】

web排错记录 在使用javaweb的过程中会出现的一些错误请在下方目录查找。 目录 错误1&#xff1a;HTTP状态404——未找到 错误2&#xff1a;导航栏下拉菜单无法点开的问题 错误3&#xff1a;字符乱码问题 错误4&#xff1a;jsp网页全部都是&#xff1f;&#xff1f;&#x…

【单片机】MSP430F149单片机,晨启,音乐播放器,蜂鸣器音乐

四、音乐播放器 任务要求&#xff1a; 设计制作一个简易音乐播放器&#xff08;通过手柄板上的蜂鸣器发声&#xff0c;播放2到4首音 乐&#xff09;&#xff0c;同时LED模块闪烁&#xff0c;给人视、听觉美的感受。 评分细则&#xff1a; 按下播放按键P15开始播放音乐&#x…

【C++】继承基础知识及简单应用,使用reportSingleClassLayout(在Visual Studio开发人员命令提示窗口)查看派生类详细信息

author&#xff1a;&Carlton tag&#xff1a;C topic&#xff1a;【C】继承基础知识及简单应用&#xff0c;使用reportSingleClassLayout&#xff08;在Visual Studio开发人员命令提示窗口&#xff09;查看派生类详细信息 website&#xff1a;黑马程序员C date&#xf…

微信小程序原生上传图片和预览+云函数上传

1.前台页面 1.1wxml问阿金 <!-- 说明一个上传页面的按钮 --> <button type"primary" bindtap"uploadPage">上传页面展示</button> <!-- 声明一个上传服务器的按钮 --> <button type"warn" bindtap"uploadSeve…