216. 组合总和 III 回溯
目录
问题描述
解决思路
关键点
代码实现
代码解析
1. 初始化结果和路径
2. 深度优先搜索(DFS)
3. 遍历候选数字
4. 递归与回溯
示例分析
复杂度与优化
回溯算法三部曲
1. 路径选择:记录当前路径
2. 递归探索:进入下一层决策
3. 撤销选择:回溯到上一层
代码框架模板
关键点解析
总结
问题描述
我们需要找出所有由 k 个不同数字组成的组合,这些数字的范围是 1 到 9,且它们的和等于 n。组合中的数字不能重复使用,且结果不能包含重复的组合。例如,当 k=3, n=7 时,唯一有效的组合是 [1,2,4]。
解决思路
这个问题可以通过回溯算法解决。核心思想是递归地尝试每一个可能的数字,逐步构建符合条件的组合,并通过剪枝优化减少无效搜索。
关键点
-
数字范围固定:所有数字只能在
1-9中选择。 -
组合唯一性:每个组合中的数字必须严格递增,避免重复(如
[1,2,4]和[2,1,4]被视为同一组合)。 -
剪枝优化:在递归过程中,提前终止不可能满足条件的分支,大幅提高效率。
代码实现
var combinationSum3 = function (k, n) {const result = [];const path = [];const dfs = (start, sum) => {// 终止条件:路径长度等于k且和等于nif (path.length === k && sum === n) {result.push([...path]);return;}// 遍历候选数字for (let i = start; i <= 9; i++) {// 剪枝1:剩余数字不够组成k个数if (path.length + (9 - i + 1) < k) break; // 剪枝2:当前和超过nif (sum + i > n) break; path.push(i);dfs(i + 1, sum + i); // 递归下一层,起始位置为i+1path.pop(); // 回溯,撤销选择}};dfs(1, 0); // 从数字1开始,初始和为0return result;
};
代码解析
1. 初始化结果和路径
-
result:存储所有符合条件的组合。 -
path:记录当前递归路径中的数字。
2. 深度优先搜索(DFS)
-
参数:
start表示当前递归的起始数字,sum表示路径中数字的当前和。 -
终止条件:当路径长度等于
k且和等于n时,将当前路径加入结果列表。
3. 遍历候选数字
-
循环范围:从
start到9,确保数字递增,避免重复组合。 -
剪枝1:
path.length + (9 - i + 1) < k
如果当前已选数字数量加上剩余可用数字数量不足k,说明无法组成有效组合,直接终止循环。
例如:k=3,当前已选1个数字,剩余可用数字是8和9(共2个),显然不够选2个。 -
剪枝2:
sum + i > n
如果当前路径和加上i已经超过n,后续更大的数字只会让和更大,无需继续搜索。
4. 递归与回溯
-
选择数字:将
i加入路径,递归调用dfs处理下一个数字。 -
撤销选择:递归返回后,将
i从路径中移除,尝试其他可能的数字。
示例分析
以 k=3, n=7 为例:
-
初始调用:
dfs(1, 0)。 -
第一层循环:
i=1,路径为[1],和为1。 -
第二层循环:
i=2(起始为2),路径为[1,2],和为3。 -
第三层循环:
i=4(起始为3),路径为[1,2,4],和为7,满足条件,加入结果。 -
回溯:递归返回,尝试其他数字,但均无法满足条件,最终结果唯一。
复杂度与优化
-
时间复杂度:最坏情况为
O(9! / (k!(9-k)!)),即组合数的时间。 -
空间复杂度:递归栈深度为
k,空间复杂度为O(k)。
通过剪枝,实际运行时间远低于理论最坏情况,因为无效分支被提前终止。
回溯算法三部曲
回溯算法是解决组合、排列、子集等问题的经典方法。它的核心思想是递归地尝试所有可能的选择,并通过“撤销选择”回到之前的状态,从而穷举所有解。其实现过程可以总结为以下三个关键步骤:
1. 路径选择:记录当前路径
在每一步递归中,将当前的选择加入路径(通常是一个数组),表示“当前正在尝试这个选择”。
对应代码:path.push(i)
作用:保存当前递归层的选择,用于后续判断是否满足条件。
示例:在组合问题中,选择数字 i 加入 path,表示尝试将 i 作为组合的一部分。
2. 递归探索:进入下一层决策
基于当前路径,递归调用函数,处理下一个选择(比如下一个数字或位置)。
对应代码:dfs(i + 1, sum + i)
作用:进入下一层递归,继续尝试剩余的选择。
示例:在组合问题中,递归时从 i+1 开始,确保数字不重复且递增,避免重复组合。
3. 撤销选择:回溯到上一层
当递归返回后(即完成当前分支的探索),将最后加入路径的元素移除,回到上一层状态,尝试其他可能的选择。
对应代码:path.pop()
作用:撤销当前层的选择,保证路径的正确性,避免污染其他分支。
示例:组合问题中,当尝试完以 i 开头的所有组合后,移除 i,尝试下一个数字。
代码框架模板
function backtrack(路径, 选择列表) {if (满足终止条件) {将路径加入结果;return;}for (选择 in 选择列表) {做选择:将选择加入路径;backtrack(路径, 新的选择列表); // 进入下一层递归撤销选择:将选择从路径移除; // 回溯}
}
关键点解析
-
路径的维护
path数组记录当前递归路径的选择,必须通过push和pop确保状态正确。 -
递归与回溯的关系
递归是纵向深入探索一条路径,回溯是横向尝试其他可能的选择。递归的终点是终止条件,回溯的触发点是递归返回后的pop。 -
剪枝优化
在组合问题中,通过以下两种剪枝大幅减少递归次数:-
剩余数字不足:
path.length + (9 - i + 1) < k
例如:如果还需要选 2 个数字,但剩余可用数字只有 1 个,直接终止。 -
和超过目标值:
sum + i > n
当前路径和已经超过n,无需继续递归
-
总结
该问题通过回溯算法枚举所有可能的组合,结合剪枝策略(剩余数字不足、和超过目标值)显著提高效率。核心在于:
-
递增选择数字:避免重复组合。
-
剪枝优化:减少不必要的递归调用。
-
回溯机制:撤销选择以尝试其他可能。
这种模式适用于许多组合问题,如子集、排列、组合总和等。
相关文章:
216. 组合总和 III 回溯
目录 问题描述 解决思路 关键点 代码实现 代码解析 1. 初始化结果和路径 2. 深度优先搜索(DFS) 3. 遍历候选数字 4. 递归与回溯 示例分析 复杂度与优化 回溯算法三部曲 1. 路径选择:记录当前路径 2. 递归探索:进入下…...
【Python 算法】动态规划
本博客笔记内容来源于灵神,视频链接如下:https://www.bilibili.com/video/BV16Y411v7Y6?vd_source7414087e971fef9431117e44d8ba61a7&spm_id_from333.788.player.switch 01背包 计算了f[i1],f[i]就没用了,相当于每时每刻只有…...
nginx的自定义错误页面
正常访问一个不存在的页面是会报404这个错误 我们可以自定义错误页面 error_page 404 /40x.html 然后调用location 最后创建文件 写入你想写的内容 最后实验成功 注意在nginx的配置文件里,注意在加分号 在写完配置时...
制作service列表并打印出来
制作service列表并打印出来 在Linux中,服务(Service)是指常驻在内存中的进程,这些进程通常监听某个端口,等待其他程序的请求。服务也被称为守护进程(Daemon),它们提供了系统所需的各…...
UML 4+1 视图:搭建软件架构的 “万能拼图”
UML 41 视图是一种全面描述软件架构的方法,以下为你详细介绍各个视图: 1.逻辑视图(Logical View) 概述:逻辑视图主要用于展现系统的功能架构,它聚焦于系统提供的功能以及这些功能的逻辑组织方式ÿ…...
tkinter 库(设计图形界面系统)
几何管理的应用 # tkinter 库 是Python的标准GUI库,提供了创建图形用户界面的功能。 tkinter是一个跨平台的GUI库,支持Windows、macOS和Linux等操作系统。它是Python的标准库之一,无需额外安装。 #tkinter.Entry 是 Tkinter 的输入框控件类&…...
WordPress汉主题
WordPress汉主题wphan.com(以下简称WP汉主题)是一个专注于WordPress中文主题与插件开发的专业团队。该团队致力于为中文用户提供高质量的WordPress主题和插件资源,帮助用户轻松创建专业且吸引人的网站。 WP汉主题提供多种功能丰富的WordPress主题,涵盖博…...
在线文档协作工具选型必看:14款产品对比
本文将深入对比14款在线文档协作工具:PingCode; 2. Worktile; 3. 语雀; 4. 金山文档; 5. WPS云文档; 6. Google Docs; 7. 轻雀文档; 8. Microsoft 365 Online; 9. 明道云文档等。 在数字化办公日益普及的今天,企业对高效协同的需求不断升级,在…...
分布式计算Ray框架面试题及参考答案
目录 简述 Ray 的架构设计核心组件及其协作流程 全局控制存储(GCS)在 Ray 中的作用是什么?如何实现高可用性? 对比 Ray 的任务(Task)与 Actor 模型,说明各自适用场景 解释 Ray 的 Object Store 如何实现跨节点数据共享与零拷贝传输 Ray 的分布式调度器如何实现毫秒级…...
Java虚拟机JVM知识点(持续更新)
JVM内存模型 介绍下内存模型 根据JDK8的规范,我们的JVM内存模型可以拆分为:程序计数器、Java虚拟机栈、堆、元空间、本地方法栈,还有一部分叫直接内存,属于操作系统的本地内存,也是可以直接操作的。 详细解释一下 程…...
【计算机网络】HTTP与HTTPS
文章目录 1. HTTP定义2. HTTP交互3. HTTP报文格式3.1 抓包工具-fiddler3.2 抓包操作3.3 报文格式3.3.1 请求报文3.3.2 响应报文 4. URL5. 请求头中的方法6. GET和POST的区别7. HTTP报头7.1 Host7.2 Content_Length7.3 Content_Type7.4 User-Agent(UA)7.5 Referer7.6 Cookie 8 状…...
数据结构:树的5种存储方案详解(C语言完整实现)
数据结构中的树结构常用来存储逻辑关系为 "一对多" 的数据。树结构可以细分为两类,分别是二叉树和非二叉树(普通树),存储它们的方案是不一样的: 二叉树的存储方案有 2 种,既可以用顺序表存储二叉…...
【蓝桥杯】 枚举和模拟练习题
系列文章目录 蓝桥杯例题 枚举和模拟 文章目录 系列文章目录前言一、好数: 题目参考:核心思想:代码实现: 二、艺术与篮球: 题目参考:核心思想:代码实现: 总结 前言 今天距离蓝桥杯还有13天&…...
WebGL图形编程实战【3】:矩阵操控 × 从二维到三维的跨越
上一篇文章:WebGL图形编程实战【2】:动态着色 纹理贴图技术揭秘 仓库地址:github…、gitee… 矩阵操控 矩阵变换 回到前面关于平移缩放、旋转的例子当中,我们是通过改变传递进去的xy的值来改变的。 在进行基础变换的时候&…...
如何把数据从SQLite迁移到PostgreSQL
## 如何把数据从SQLite迁移到PostgreSQL 文章目录 1、DB-Engines 中的SQLite 和 PostgreSQL2、SQLite安装和测试2.1、编译安装SQLite2.2、数据测试 3、Postgresql安装和测试3.1、编译安装postgresql3.2、测试 4、pgloader安装5、数据迁移和验证5.1、准备参数文件5.2、数据迁移…...
Qt使用QGraphicsView绘制线路图————附带详细实现代码
文章目录 0 效果1 核心1.1 简单示例1.1.1 解读 1.2 创建用户交互1.2.1 完整示例 1.3 创建图形元1.3.1 绘制直线1.3.2 绘制贝塞尔曲线1.3.3 绘制图片 1.4 移动的小车 2 使用自定义视图类参考 0 效果 视图中包含线路、道岔、信号灯、火车。 下图为站点信号灯: 下图…...
【系统性偏见:AI照出的文明暗伤与生存悖论】
系统性偏见:AI照出的文明暗伤与生存悖论 第一层:偏见如何从数据中“遗传” 当某科技公司用十年招聘数据训练AI筛选简历时,系统悄然学会:提到"女性工程师协会"的简历,获得面试的概率自动下降37%——这相当于…...
【Linux】调试器——gdb使用
目录 一、预备知识 二、常用指令 三、调试技巧 (一)监视变量的变化指令 watch (二)更改指定变量的值 set var 正文 一、预备知识 程序的发布形式有两种,debug和release模式,Linux gcc/g出来的二进制…...
【数据分享】2000—2024年我国乡镇的逐年归一化植被指数(NDVI)数据(年最大值/Shp/Excel格式)
之前我们分享过2000-2024年我国逐年的归一化植被指数(NDVI)栅格数据,该逐年数据是取的当年月归一化植被指数(NDVI)的年最大值!另外,我们基于此年度栅格数据按照行政区划取平均值,得到…...
Shell 不神秘:拆解 Linux 命令行的逻辑与效率
初始shell shell的概述 什么是shell 本质 shell本质是脚本文件:完成批处理。 比如 有一个文件 中十个文件,这十个文件中每个文件又有是个子文件,由人来处理,很麻烦,但如果写一个脚本文件,让脚本来替我…...
win 远程 ubuntu 服务器 安装图形界面
远程结果:无法使用docker环境使用此方法 注意要写IP和:数字 在 ubuntu 服务器上安装如下: # 安装 sudo apt-get install tightvncserver # 卸载 sudo apt purge tightvncserver sudo apt autoremove#安装缺失的字体包: sudo apt update s…...
大模型高质量rag构建:A Cheat Sheet and Some Recipes For Building Advanced RAG
原文:A Cheat Sheet and Some Recipes For Building Advanced RAG — LlamaIndex - Build Knowledge Assistants over your Enterprise DataLlamaIndex is a simple, flexible framework for building knowledge assistants using LLMs connected to your enterpris…...
【Qt】游戏场景和图元
一:图元 advance函数: 在 Qt 框架里,QGraphicsItem 是用于在 QGraphicsScene 中绘制图形项的基类。advance(int phase) 是 QGraphicsItem 类的一个虚函数,其主要用途是让图形项在场景的动画或更新过程里完成特定的逻辑操作。 p…...
C++位运算精要:高效解题的利器
引言 在算法竞赛和底层开发中,位运算(Bit Manipulation)因其极高的执行效率而广受青睐。它能在O(1)时间复杂度内完成某些复杂操作,大幅优化程序性能。本文系统梳理C位运算的核心技巧,涵盖基础操作、经典应用、优化策略…...
几种常见的.NET单元测试模拟框架介绍
目录 1. Moq 2. NSubstitute 3. AutoFixture 4. FakeItEasy 总结对比 单元测试模拟框架是一种在软件开发中用于辅助单元测试的工具。 它的主要作用是创建模拟对象来替代真实对象进行测试。在单元测试中,被测试的代码可能依赖于其他组件或服务,如数…...
开源的CMS建站系统可以随便用吗?有什么需要注意的?
开源CMS建站系统虽然具有许多优点,但并非完全“随便用”。无论选哪个CMS系统,大家在使用的时候,可以尽可能地多注意以下几点: 1、版权问题 了解开源许可证:不同的开源CMS系统采用不同的开源许可证,如GPL、…...
初始ARM
ARM最基础的组成单元。 最小系统:能系统能够正常工作的最少器件构成的系统 。 一、CPU基础定义 1. 核心定位 计算机三大核心部件: CPU(运算与控制)内部存储器(数据存储)输入/输出设备(数据交互…...
vue配置.eslintrc、.prettierrc详解
一、eslint简介 ESLint 是一个用于识别和报告 JavaScript 代码中潜在问题的静态代码分析工具。它可以帮助开发人员和团队维护一致的代码风格,减少错误,并确保代码质量。以下是 ESLint 的一些关键特点和功能: 1.静态代码分析:ESLi…...
DataPlatter:利用最少成本数据提升机器人操控的泛化能力
25年3月来自中科院计算所的论文“DataPlatter: Boosting Robotic Manipulation Generalization with Minimal Costly Data”。 视觉-语言-动作 (VLA) 模型在具身人工智能中的应用日益广泛,这加剧对多样化操作演示的需求。然而,数据收集的高成本往往导致…...
诠视科技MR眼镜如何安装apk应用
诠视科技MR眼镜如何安装apk应用 1、使用adb工具安装1.1 adb工具下载1.2 解压adb文件1.3 使用adb安装apk1.4 常用adb命令 2、拷贝到文件夹安装 1、使用adb工具安装 1.1 adb工具下载 点击下面的链接开始下载adb工具,下载结束以后解压文件。 下载链接: https://down…...
