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年成立以来,一直专注于为汽车制造业提供自动化输送系统、车辆装配的合装技术和…...

uniapp多图上传uni.chooseImage上传照片uni.uploadFile,默认上传9张图
uniapp多图上传uni.chooseImage上传照片uni.uploadFile 代码示例: /**上传照片 多图*/getImage() {uni.chooseImage({count: 9, //默认9sizeType: [original, compressed], //可以指定是原图还是压缩图,默认二者都有sourceType: [album], //从相册选择/…...

MySQL——内置函数
时间函数 select * from msg where date_add(sendtime, interval 2 minute) > now(); 理解: ------------------------------|-----------|-------------|------------------ 初始时间 now() 初始时间2min 字符串 length函数返回字符串长度,以字节为…...

2024年最新版小程序云开发数据模型的开通步骤,支持可视化数据库管理,支持Mysql和NoSql数据库,可以在vue3前端web里调用操作
小程序官方又改版了,搞得石头哥不得不紧急的再新出一版,教大家开通最新版的数据模型。官方既然主推数据模型,那我们就先看看看新版的数据模型到底是什么。 一,什么是数据模型 数据模型是什么 数据模型是一个用于组织和管理数据的…...

智慧水库大坝安全监测预警系统解决方案
前言 水库大坝作为重要的水利设施,承载着防洪涝、灌溉、发电等功能,关系着无数人的生命财产安全,一旦发生意外事故,后果将不堪设想,因此需要建立一套水库大坝安全监测预警系统解决方案。 系统概述 水库大坝安全监测…...

基于SpringBoot+VUE的社区团购系统(源码+文档+部署)
主要内容:Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能与大数据、单片机开发、物联网设计与开发设计、简历模板、学习资料、面试题库、技术互助、就业指导等 业务范围:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写…...

LeetCode 3151. 特殊数组 I【数组】简单【Py3,C++,Java,GO,Rust】
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...

超级字符串技能:提升你的编码游戏
嘿嘿,uu们,今天咱们来详解字符函数与字符串函数,好啦,废话不多讲,开干! 1.:字符分类函数 C语言中又一系列的函数是专门做字符分类的,也就是一个字符属于什么类型的字符的,这些函数的使用需要包含头文件ctype.h 这些函数的使用方法都十分类似,博主在这里就举两到三个…...

米联客-FPGA程序设计Verilog语法入门篇连载-16 Verilog语法_时钟分频设计
软件版本:无 操作系统:WIN10 64bit 硬件平台:适用所有系列FPGA 板卡获取平台:https://milianke.tmall.com/ 登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑! 1概述 本小节讲解Verilog语法的时钟…...

【Echarts】custom自定义图表实现甘特图
效果图 主要注意点: 1、右上角图例visualMap实现 2、visualMap增加formatter 3、series使用custom自定义图表,encode解析四维数组。核心是renderItem方法,必填项,且需要注意要全部定义在options里面!!&…...

【高等代数笔记】003线性方程组的解法(一)
1. 线性方程组的解法 1.1 解线性方程组的矩阵消元法 【例1】解线性方程组 { x 1 3 x 2 x 3 2 3 x 1 4 x 2 2 x 3 9 − x 1 − 5 x 2 4 x 3 10 2 x 1 7 x 2 x 3 1 \left\{\begin{array}{ll} x_{1}3x_{2}x_{3}2 \\ 3x_{1}4x_{2}2x_{3}9 \\ -x_{1}-5x_{2}4x_{3}10 \\…...