leetcode39组合总和
题目描述
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 对于给定的输入,保证和为 target 的不同组合数少于 150 个。
示例 1:
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
解题思路
回溯算法:这类问题的典型解法是使用回溯算法,递归地构建可能的组合,并在找到符合条件的组合时将其加入结果集。
剪枝:为了优化算法,我们可以对已经超过目标值的组合进行剪枝,避免无效的递归。
排序:先对候选数字排序,方便后续的剪枝操作。
解题步骤
1.排序候选数字:为了方便剪枝操作,先将候选数字排序。排序后的候选数字为 [3, 4, 7, 8]。
2.回溯查找组合:从第一个候选数字开始,尝试所有可能的组合,计算每个组合的和。如果和等于目标值,则将其添加到结果集。如果和超过目标值,则停止当前路径的搜索(剪枝)。
代码实现
func combinationSum(candidates []int, target int) [][]int {// 1.初始化var result [][]intvar combination []int// 2.排序以便于剪枝sort.Ints(candidates)// 3.声明一个回溯函数var backtrack func(start, target int)backtrack = func(start, target int) {if target == 0 {// 4.找到一个符合条件的组合,加入结果集result = append(result, append([]int(nil), combination...))return}for i := start; i < len(candidates); i++ {if candidates[i] > target {// 5.剪枝:如果当前候选数字大于剩余目标值,直接退出循环break}// 6.选择当前候选数字combination = append(combination, candidates[i])// 7.因为数字可以重复使用,所以传入 i 作为下一个开始索引backtrack(i, target-candidates[i])// 8.回溯:撤销选择combination = combination[:len(combination)-1]}}// 9.回溯backtrack(0, target)// 10.返回结果return result
}
代码测试
func main() {// 测试用例candidates := []int{2, 3, 6, 7}target := 7// 打印结果fmt.Println("Candidates:", candidates)fmt.Println("Target:", target)fmt.Println("Combinations:", combinationSum(candidates, target))
}
测试结果

关于题目疑问
Q1 为什么用回溯来解决这个问题?
- 问题的本质是枚举所有可能的组合
这道题的目标是找出所有数字组合,使得这些组合的数字之和等于目标值。这类问题的本质是需要枚举所有可能的组合,并对每个组合进行验证。回溯算法擅长于这种“试探并撤销”的过程,可以系统地枚举所有可能的解。
- 回溯算法可以有效地处理组合问题
回溯算法通过递归地构建解空间树(每个节点表示一个选择),探索每一个可能的选择路径。当发现某条路径不能满足条件时,算法会“回溯”到上一步,尝试其他路径。
递归的便利性:回溯算法可以自然地处理递归场景,例如在组合问题中,通过递归函数,我们可以方便地处理当前组合中的每一个元素,并且可以灵活地调整递归函数的参数来处理不同的子问题。
逐步构建解的能力:回溯算法可以逐步构建可能的解,并在找到满足条件的解时立即将其记录下来。同时,如果当前路径已经不可能生成一个有效的解,回溯算法可以立刻剪枝并返回到上一个状态,从而避免不必要的计算。
- 剪枝优化减少不必要的计算
在回溯算法中,剪枝是一种重要的优化技术。通过剪枝,可以在搜索空间过大时,排除那些明显不可能产生有效解的路径,从而减少计算量。
排序+剪枝:在这道题中,先对候选数组进行排序,然后在递归中,如果当前选择的数字已经超过了剩余的目标值,我们就可以直接停止对该路径的探索,因为后续的数字只会更大,不可能满足要求。这大大提高了效率。
- 灵活性和通用性
回溯算法不仅能解决这道题,还能适应很多类似的组合问题。例如,LeetCode 上的许多其他组合、排列、子集问题(如组合总和 II、全排列、子集等)都可以通过回溯算法解决。回溯算法的灵活性和通用性使它成为处理这类问题的首选。
- 易于理解和实现
尽管回溯算法在最坏情况下的时间复杂度较高,但它相对容易理解和实现。特别是在找出所有解的情况下,回溯算法的逻辑是清晰的:尝试每一个可能的路径,直到找到所有符合条件的路径为止。
结论
回溯算法之所以适合用来解决这道题,是因为它能够系统地、全面地遍历所有可能的组合,并且在找到不符合条件的路径时,可以迅速回退并尝试其他路径。结合剪枝等优化措施,回溯算法能够在保持简洁明了的同时,尽可能地高效地解决问题。这使得回溯算法成为解决组合总和问题的理想选择。
Q2 回溯过程是怎样的?
回溯过程详细解释
我们以代码中 combinationSum 函数的 backtrack 递归函数为例,假设输入的 candidates 为 [2, 3, 6, 7],target 为 7。
初始状态
candidates: [2, 3, 6, 7]
target: 7
combination: [](当前组合,开始时为空)
result: [](存储所有符合条件的组合)
回溯的每一步
第一层递归(从 candidates[0] 开始)
选择 2:combination = [2],新的 target = 7 - 2 = 5。
继续调用 backtrack(0, 5)。
第二层递归(仍然从 candidates[0] 开始)
选择 2:combination = [2, 2],新的 target = 5 - 2 = 3。
继续调用 backtrack(0, 3)。
第三层递归(仍然从 candidates[0] 开始)
选择 2:combination = [2, 2, 2],新的 target = 3 - 2 = 1。
继续调用 backtrack(0, 1)。
第四层递归(仍然从 candidates[0] 开始)
选择 2:combination = [2, 2, 2, 2],新的 target = 1 - 2 = -1。
由于 target 小于 0,回溯:移除最后一个 2,组合变回 combination = [2, 2, 2],然后尝试 candidates[1]。
尝试 candidates[1](在第三层递归中)
选择 3:combination = [2, 2, 3],新的 target = 3 - 3 = 0。
由于 target 等于 0,将 [2, 2, 3] 加入 result。
回溯:移除 3,组合变回 combination = [2, 2]。
继续尝试 candidates[2] 和 candidates[3](在第二层递归中)
发现它们都使 target 小于 0,所以不进一步递归,继续回溯。
回到第一层递归(尝试 candidates[1])
选择 3:combination = [3],新的 target = 7 - 3 = 4。
继续调用 backtrack(1, 4),接下来的步骤类似,尝试不同组合。
尝试 candidates[2] 和 candidates[3]
combination = [6],combination = [7] 最终找到另一个组合 [7]。
回溯树的结构
第一层选择 2,进行回溯,深度优先搜索所有可能的组合。
回溯到第一层,选择 3,然后继续尝试。
最终遍历所有可能的组合,找到满足条件的组合 [2, 2, 3] 和 [7]。
总结
选择:在每一步,我们选择一个候选数字,并将其加入当前组合。
递归:对新组合进行递归,尝试构造下一个数字。
剪枝:如果当前组合的和超过目标值,我们停止递归并回溯。
回溯:如果递归到达底部但不符合条件(和超过或等于目标值),我们回到上一步,撤销上一步的选择,尝试下一个候选数字。
通过这样不断尝试、撤销的过程,算法能够遍历所有可能的组合,最终得到所有符合条件的结果。
Q3 []int(nil) 的含义?
[]int(nil) 是一种显式创建 nil 切片的方式。它的作用等同于 var s []int,即创建一个 nil 切片。
为什么使用nil?
在 Go 语言中,切片是一种动态数组,它本质上是对数组的一个引用。切片有三个字段:指向数组的指针、切片的长度、和切片的容量。
nil 切片:一个 nil 切片是一个没有分配底层数组的切片,它的长度和容量都为 0。你可以通过 var s []int 或 s := []int(nil) 来声明一个 nil 切片。
var s []int
fmt.Println(s == nil) // true
在某些情况下,尤其是在回溯算法中,我们需要确保创建的是一个空切片(而不是一个已经被初始化的非 nil 的切片)。[]int(nil) 显式地创建一个 nil 切片,这样在后续的操作中,可以避免不必要的内存分配或初始化。
result = append(result, append([]int(nil), combination...))
[]int(nil) 创建了一个 nil 切片。
append([]int(nil), combination…) 创建了一个包含 combination 元素的新切片,这个新切片和 combination 不共享底层数组,是一个独立的拷贝。
与空切片 []int{} 的区别?
虽然 []int(nil) 和 []int{} 都可以用于创建空切片,但它们在初始化时的内存分配行为略有不同:
[]int(nil):创建的是一个 nil 切片,没有分配任何底层数组。这个切片的长度和容量为 0,并且底层数组指针为 nil。
[]int{}:创建的是一个非 nil 的空切片,它的长度为 0,容量也为 0,但底层数组指针不为 nil(尽管该数组本身为空)。
在实际编程中,选择 []int(nil) 还是 []int{} 主要取决于具体的需求。例如,如果你希望确保切片是 nil(比如用于判断或处理),可以使用 []int(nil);如果你只是需要一个空的可用切片,则使用 []int{}。
相关文章:
leetcode39组合总和
题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被选…...
【JPCS独立出版,EI稳定检索】2024年工业机器人与先进制造技术国际学术会议(IRAMT 2024,9月27-29)
2024年工业机器人与先进制造技术国际学术会议(IRAMT 2024)将于2024年9月27-29日在中国成都举办。 此次会议将围绕工业机器人、机电技术、机械及制造等领域的最新研究成果展开讨论,并广泛邀请了国内外领域内的著名专家与学者。会议旨在搭建一个…...
Fal.ai Flux 1-Pro/Viva.ai/哩布哩布AI:AI绘图部分免费工具+原图提示词Prompt
目录 #1 找软件 #2 懂提示词 #3 更难的一步,会英文 我个人认为,想要玩文生图,你要会3个步骤: #1 找软件 主流文生图软件:Midjourney、Stable Diffusion、Dall-E 3 巧了,我用的都是小众、免费的画笔工…...
C++学习笔记----2、使用C++进行优雅编程(十)---- 格式化
许多人因为编程风格的问题被搞得焦头烂额,就因为对于在if中使用几个空格争论不休,导致友谊的小船说翻就翻。如果公司有相应的编程规范,只能说你比较幸运。因为有可能你不喜欢这些规范,但做为一个正常人来讲,至少有规范…...
双指针| Java | (hot100) 力扣283, 11, 15, 42做题总结
leetcode 11 盛最多水的容器 双层for循环暴力 超出时间限制 class Solution {public int maxArea(int[] height) {int h0;int v0;for(int i0; i<height.length; i) {for(int ji1; j<height.length; j) {h Math.min(height[i],height[j]);v Math.max(v, h*(j-i));}}…...
matlab求解方程
【MATLAB】求解含有三角函数的方程_matlab求解三角函数方程-CSDN博客 Matlab求解方程或函数的根,root,fzero,solve,fsolve的区别_matlab root-CSDN博客 非线性方程(组):MATLAB内置函数 solve, vpasolve, fsolve, fzero, roots [MATLAB] - GentleMin - …...
MySQL基础--视图,存储过程
介绍 视图是一种虚拟存在的表,视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。 通俗的讲,视图只保存了查询的 SQL 逻辑,不保存查询结果,所以我…...
学习记录第二十六天
进程运行 1,子进程和父进程做相同的事----创建子进程 执行任务 2,子进程做与父进程不同的事 ----fork exec exec族 l VS v :主要是第二个参数的传参方式不同 p :表示寻找可执行文件 是通过PATA环境变量 e : 表示可以给…...
Polars简明基础教程十一:可视化(一)
到本次讲座结束时,你将能够: 使用Polars的内部plot方法从Polars创建图表使用外部绘图库从Polars创建图表了解这些库如何支持Polars 通常,需要可视化库的最新版本来实现最大程度的兼容性 import polars as plimport hvplot as hv import ma…...
实战项目:贪吃蛇游戏的实现(上)
前言 Hello, 今天我们来一起完成一个实战项目:贪吃蛇。 相信大家都不会对这个游戏感到陌生,贪吃蛇游戏是久负盛名的游戏,他和俄罗斯方块,扫雷游戏等游戏位列世界经典游戏之列。这次我们旨在通过实战项目贪吃蛇的实现,…...
SHT30温湿度传感器全解析——概况,性能,MCU连接,样例代码
常见温湿度传感器测量范围:(价格仅供参考,具体性能要看折线图) 型号DHT11DHT20AHT10AHT20AHT30SHT20价格¥ 2.49¥3.04¥ 1.9¥1.4¥ 1.3¥5.5温度测量范围20—90%RH0—100%RH0—100%RH0—…...
SQL server 同环比计算模板
1、计算 月 年 季度的环比和同比 计算公式如下: 环比增长率 (本期数 - 上期数) / |上期数| 100% 同比增长率 (本期数 - 同期数) / |同期数| * 100% --- dbo.ads_erp_finance_gross_profit_actual_invoice_yoy_m…...
python发送外部请求
在Python中,服务器发送外部请求是一个常见的操作,尤其是在需要集成不同服务或API时。有多种库可以帮助你完成这项任务,但最流行和广泛使用的库之一是requests。以下是如何使用requests库在Python服务器中发送外部请求的基本步骤: …...
c++并发编程面试题
1. C中lock_guard和unique_lock的区别? 在C中,lock_guard和unique_lock都是用于管理互斥锁的类,它们提供了一种 RAII(Resource Acquisition Is Initialization)机制来确保锁在作用域结束时自动释放。尽管它们的目的相…...
K8S上安装LongHorn(分布式块存储) --use
要在 Kubernetes上安装 LongHorn,您可以按照以下步骤进行操作: 准备工作 参考 官网教程将LongHorn只部署在k8s-worker5节点上。https://github.com/longhorn/longhorn 安装要求 Each node in the Kubernetes cluster where Longhorn is installed must f…...
2024年前端技术发展趋势分析
2024年的前端技术发展趋势继续受到快速变化的技术环境和不断增长的用户期望的影响。以下是2024年前端技术发展的几个关键趋势: 1. Web 组件和自定义元素 Web 组件技术(包括 Shadow DOM、HTML Templates 和 Custom Elements)正在成为构建可重…...
spring boot 笔记大杂烩
一,springboot项目创建 springboot创建时idea会打开start.spring.io失败报错 可以手动打开这个页面,然后选择maven项目,然后修改group和name名然后添加依赖web,然后生成项目包,解压缩后用idea打开就能用了 运行后报错…...
如何在香港云服务器上优化网站性能?
在香港云服务器上优化网站性能可以通过以下几种方式进行,确保用户从全球各地访问时获得快速、稳定的体验: 1. 使用内容分发网络 (CDN) 优势:CDN可以将静态内容(如图像、视频、CSS、JavaScript文件)缓存到全球多个节点…...
STM32低功耗与备用备份区域
STM的备份备用区域其实就是两个区块:BKP和RTC。低功耗则其实是STM32四种模式中的三种耗能很低的模式。 目录 一:备用区域 1.BKP 2.RTC 二:低功耗模式 1.睡眠模式: 2.停机模式: 3.待机模式: 一&…...
武汉某汽配公司携手三品软件 共绘PLM项目新蓝图
近日,三品软件与武汉某汽配公司达成战略合作,双方将共同启动PLM项目,以助力该公司在汽车制造业的研发管理领域实现全面升级。 客户简介 该公司自2008年成立以来,一直专注于为汽车制造业提供自动化输送系统、车辆装配的合装技术和…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...
MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
