代码随想录训练营Day27 | 77. 组合 | 216.组合总和III | 17.电话号码的字母组合
学习文档:代码随想录 (programmercarl.com)
视频链接:代码随想录算法公开课 | 最强算法公开课 | 代码随想录 (programmercarl.com)
Leetcode 77. 组合
题目描述
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2 输出: [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ]
示例 2:
输入:n = 1, k = 1 输出:[[1]]
提示:
1 <= n <= 201 <= k <= n
解题思路
这是回溯算法的经典题目,可以将题目抽象为N叉树来理解回溯算法。这颗树的初始集合就是[1,2,3,4],从左往右取数,取过的数就不再取,避免出现重复集合,每个节点需要一个for循环来遍历,所以需要一个startindex来控制遍历的起始值,需要用一维数组来存放结果,用二维数组来存放所有满足的结果。

图中可以发现n相当于树的宽度,k相当于树的深度。
回溯算法三部曲:
1. 确定递归函数的返回值合参数
n,k是题目给出,startIndex来控制每次for循环的起始位置
vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件单一结果
void backtracking(int n, int k, int startIndex)
2.确定回溯函数的终止条件
当path这个数组的大小如果达到k,说明找到了一个子集大小为k的组合了,在图中path存的就是根节点到叶子节点的路径。
if (path.size() == k) {result.push_back(path);return;
}
3.确定单层搜索的过程
回溯法的搜索过程就是一个树型结构的遍历过程,在图中,可以看出for循环用来横向遍历,递归的过程是纵向遍历。
for (int i = startIndex; i <= n; i++) { // 控制树的横向遍历path.push_back(i); // 处理节点backtracking(n, k, i + 1); // 递归:控制树的纵向遍历,注意下一层搜索要从i+1开始path.pop_back(); // 回溯,撤销处理的节点
}
完整代码
class Solution {
private:vector<vector<int>> result; // 存放符合条件结果的集合vector<int> path; // 用来存放符合条件结果void backtracking(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); // 处理节点backtracking(n, k, i + 1); // 递归path.pop_back(); // 回溯,撤销处理的节点}}
public:vector<vector<int>> combine(int n, int k) {result.clear(); // 可以不写path.clear(); // 可以不写backtracking(n, k, 1);return result;}
};
剪枝优化
回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的
举一个例子,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。

可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了
-
已经选择的元素个数:path.size();
-
还需要的元素个数为: k - path.size();
-
在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历
为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。
所以优化之后的for循环是:
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置
完整代码
class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(int n, int k, int startIndex) {if (path.size() == k) {result.push_back(path);return;}for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) { // 优化的地方path.push_back(i); // 处理节点backtracking(n, k, i + 1);path.pop_back(); // 回溯,撤销处理的节点}}
public:vector<vector<int>> combine(int n, int k) {backtracking(n, k, 1);return result;}
};
Leetcode 216. 组合总和 III
题目描述
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
- 只使用数字1到9
- 每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例 1:
输入: k = 3, n = 7 输出: [[1,2,4]] 解释: 1 + 2 + 4 = 7 没有其他符合的组合了。
示例 2:
输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]] 解释: 1 + 2 + 6 = 9 1 + 3 + 5 = 9 2 + 3 + 4 = 9 没有其他符合的组合了。
示例 3:
输入: k = 4, n = 1 输出: [] 解释: 不存在有效的组合。 在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。
提示:
2 <= k <= 91 <= n <= 60
解题思路
这题相对于上一题就是多了一个限制,要找到和为n的k个整数,整个集合是固定的。
完整代码
class Solution {
vector<vector<int>> result;
vector<int> path;
void backtracking(int targetSum, int k, int sum, int startIndex) {if (path.size() == k) {if(sum == targetSum) {result.push_back(path);}return; // 如果path.size() == k 但sum != targetSum 直接返回}for (int i = startIndex; i <= 9; i++) { sum += i;path.push_back(i); backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndexsum -= i; // 回溯path.pop_back(); // 回溯,撤销处理的节点}
}
public:vector<vector<int>> combinationSum3(int k, int n) {backtracking(n, k, 0, 1);return result;}
};
剪枝优化
已选元素总和如果已经大于n(图中数值为4)了,那么往后遍历就没有意义了,直接剪掉
那么剪枝的地方可以放在递归函数开始的地方,剪枝代码如下:
if (sum > targetSum) { // 剪枝操作return;
}
完整代码
class Solution {
private:vector<vector<int>> result; // 存放结果集vector<int> path; // 符合条件的结果void backtracking(int targetSum, int k, int sum, int startIndex) {if (sum > targetSum) { // 剪枝操作return; }if (path.size() == k) {if (sum == targetSum) result.push_back(path);return; // 如果path.size() == k 但sum != targetSum 直接返回}for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) { // 剪枝sum += i; // 处理path.push_back(i); // 处理backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndexsum -= i; // 回溯path.pop_back(); // 回溯}}public:vector<vector<int>> combinationSum3(int k, int n) {result.clear(); // 可以不加path.clear(); // 可以不加backtracking(n, k, 0, 1);return result;}
};
Leetcode 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 <= 4digits[i]是范围['2', '9']的一个数字。
解题思路
可以使用map或者定义一个二维数组,例如:string letterMap[10],来做映射
const string letterMap[10] = {"", // 0"", // 1"abc", // 2"def", // 3"ghi", // 4"jkl", // 5"mno", // 6"pqrs", // 7"tuv", // 8"wxyz", // 9
};

图中可以看出遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,输出["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。
回溯三部曲
1.确定回溯函数的参数
参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index,这个index与之前的startIndex不同,这个index是记录遍历第几个数字了(例如输入“23”,可以用来表示现在是遍历“2”对应的字符还是“3”),就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
vector<string> result;
string s;
void backtracking(const string& digits, int index)
2.确定终止条件
例如输入用例"23",两个数字,那么根节点往下递归两层就可以了,叶子节点就是要收集的结果集。那么终止条件就是如果index 等于 输入的数字个数(digits.size)了(本来index就是用来遍历digits的)。然后收集结果,结束本层递归。
if (index == digits.size()) {result.push_back(s);return;
}
3.确定单层遍历逻辑
首先要取index指向的数字,并找到对应的字符集(手机键盘的字符集)。然后for循环来处理这个字符集,代码如下:
int digit = digits[index] - '0'; // 将index指向的数字转为int
string letters = letterMap[digit]; // 取数字对应的字符集
for (int i = 0; i < letters.size(); i++) {s.push_back(letters[i]); // 处理backtracking(digits, index + 1); // 递归,注意index+1,一下层要处理下一个数字了s.pop_back(); // 回溯
}
完整代码
class Solution {
private:const string letterMap[10] = {"", // 0"", // 1"abc", // 2"def", // 3"ghi", // 4"jkl", // 5"mno", // 6"pqrs", // 7"tuv", // 8"wxyz", // 9};
public:vector<string> result;string s;void backtracking(const string& digits, int index) {if (index == digits.size()) {result.push_back(s);return;}int digit = digits[index] - '0'; // 将index指向的数字转为intstring letters = letterMap[digit]; // 取数字对应的字符集for (int i = 0; i < letters.size(); i++) {s.push_back(letters[i]); // 处理backtracking(digits, index + 1); // 递归,注意index+1,一下层要处理下一个数字了s.pop_back(); // 回溯}}vector<string> letterCombinations(string digits) {s.clear();result.clear();if (digits.size() == 0) {return result;}backtracking(digits, 0);return result;}
};
相关文章:
代码随想录训练营Day27 | 77. 组合 | 216.组合总和III | 17.电话号码的字母组合
学习文档:代码随想录 (programmercarl.com) 视频链接:代码随想录算法公开课 | 最强算法公开课 | 代码随想录 (programmercarl.com) Leetcode 77. 组合 题目描述 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以…...
Linux文件重定向文件缓冲区
目录 一、C文件接口 二、系统文件I/O 2.1认识系统文件I/O 2.2系统文件I/O 2.3系统调用和库函数 2.4open( )的返回值--文件描述符 2.5访问文件的本质 三、文件重定向 3.1认识文件重定向 3.2文件重定向的本质 3.3在shell中添加重定向功能 3.4stdout和stderr 3.5如何理…...
训练贪吃蛇ai的后续记录
发现可以结合遗传算法的思路,产生更好的效果。 即每训练一段时间,就停下来测试一下新模型的效果。如果效果优于记录中最好的,则继续导入该模型并训练。重复几次,效果可能更好。 例如,昨晚我便通过唯一一个在十次测试中…...
WPF 手撸插件 八 操作数据库一
1、本文将使用SqlSugar创建Sqlite数据库,进行入门的增删改查等操作。擦,咋写着写着凌乱起来了。 SqlSugar官方文档:简单示例,1分钟入门 - SqlSugar 5x - .NET果糖网 2、环境SqlSugar V5.0版本需要.Net Framework 4.6 ࿰…...
代数结构基础 - 离散数学系列(八)
目录 1. 群(Group) 群的定义 群的示例 2. 环(Ring) 环的定义 环的示例 3. 域(Field) 域的定义 域的示例 域在密码学中的应用 4. 实际应用场景 1. 对称性与加密 2. 误差检测与纠正 3. 数据编码…...
函数的arguments为什么不是数组?如何转化为数组?
因为arguments本身并不能调用数组方法,它是一个另外一种对象类型,只不过属性从0开始排,依次为0 1 2…最后还有callee和length属性,我们也把这样的对象成为类数组。 常见的类数组还有: 1.用getElementsByTagName/Class…...
Java之反射
目录 反射 定义 主要用途 反射相关的类 Class类中【获得类相关方法】 Class类中【获得类中属性相关的方法】 Class类中【获得类中注解相关的方法】 Class类中【获得类中构造器相关的方法】 Class类中【获得类中方法相关的方法】 获得Class对象 代码示例1 代码示例…...
3dsMax添加天空盒
点击渲染,环境 , 点击位图 找到要设置的天空HDR,可以使用HDR(EXR)贴图 一个可以下载HDR贴图的网站 https://polyhaven.com/hdris在渲染的时候不要使用使用微软输入法,3dsmax会卡死, 在渲染的时候不要使用使用微软…...
C语言的类型提升机制
概念 在C语言中,整数类型按照其大小可以分为以下几类(从小到大): charshortintlonglong long 当在表达式中涉及这些类型的混合运算时,较小的类型会被提升为较大的类型。具体规则如下: ①char 和 short …...
Pandas和Seaborn数据可视化
Pandas数据可视化 学习目标 本章内容不需要理解和记忆,重在【查表】! 知道数据可视化的重要性和必要性知道如何使用Matplotlib的常用图表API能够找到Seaborn的绘图API 1 Pandas数据可视化 一图胜千言,人是一个视觉敏感的动物,大…...
爬虫(Python版本)
1.爬虫的法律问题 爬虫技术(Web Scraping)指通过程序自动访问网页并提取其中的数据。在使用爬虫的过程中,涉及到一些法律法规和合规性问题。 常见法律风险 ①未经授权的访问:很多网站对爬虫行为设置了限制。如果未获得授权就进行…...
【分布式训练 debug】VS Code Debug 技巧:launch.json实用参数
VS Code Debug技巧:launch.json实用参数 在使用Visual Studio Code (VS Code)进行调试时,launch.json文件是一个强大的工具,它允许你自定义调试会话。以下是一些实用的参数,可以帮助你更有效地调试Python代码。 1. 调试第三方库…...
pycharm连接linux服务器需要提前安装ssh服务
在 Debian 或 Ubuntu 系统上,使用 APT: bash复制代码 sudo apt-get install openssh-server 在基于 RPM 的系统如 CentOS 或 RHEL 上,使用 YUM 或 DNF: bash复制代码 sudo yum install openssh-server 或对于较新的 RHEL/Cent…...
通信工程学习:什么是LAN局域网、MAN城域网、WAN广域网
LAN局域网、MAN城域网、WAN广域网 LAN(Local Area Network,局域网)、MAN(Metropolitan Area Network,城域网)和WAN(Wide Area Network,广域网)是计算机网络中根据覆盖范围…...
LeetCode热题100速通
一丶哈希 1、两数之和(简单) 给定一个整数数组 n u m s nums nums 和一个整数目标值 t a r g e t target target,请你在该数组中找出 和为目标值 t a r g e t target target 的那 两个 整数,并返回它们的数组下标。 你可以假设…...
Python代码编写KDJ指标
KDJ指标由三部分组成:K值、D值、J值,主要用于分析股票市场的超买超卖状态及股价波动的趋势。博主记录学习编写KDJ指标线 import numpy as npdef calculate_kdj(close_prices, n9, m13, m23):"""计算KDJ指标:param close_prices: 收盘价序…...
传统少数民族物品检测系统源码分享
传统少数民族物品检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer…...
深度学习中的迁移学习:预训练模型微调与实践
深度学习中的迁移学习:预训练模型微调与实践 目录 💡 迁移学习的核心概念🧠 预训练模型的使用:ResNet与VGG的微调🏥 迁移学习在医学图像分析中的应用🔄 实践中的迁移学习微调过程 1. 💡 迁移学…...
原生input实现时间选择器用法
2024.10.08今天我学习了如何用原生的input,实现时间选择器用法,效果如下: 代码如下: <div><input id"yf_start" type"text"> </div><script>$(#yf_start).datepicker({language: zh…...
对象的概念
对象是编程中一个重要的概念,尤其在面向对象编程(OOP)中更为核心。简单来说,对象是一种数据结构,它可以存储相关的数据和功能。以下是关于对象的详细描述: 1. 对象的定义 对象是属性(数据&…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
