当前位置: 首页 > news >正文

深搜练习(组合总和)(7)

一.题目

39. 组合总和 - 力扣(LeetCode)

二.思路讲解

2.1 思路讲解

本题与之前组合问题的核心区别在于:同一个数字可以被无限重复选取。这意味着在递归过程中,我们不能像之前那样用i+1强制跳过当前元素,而应该允许继续选择当前元素。因此,递归调用时,下一层的pos参数不增加(仍从i开始),这样才能重复使用同一数字。

另一个重要区别是剪枝策略:由于可以重复选取,我们需要防止无效的无限递归。可以在递归过程中检查当前累积和sum是否已经超过target,一旦超过,就可以立即剪枝(因为后续元素更大,和只会更大),无需继续探索。

递归框架:使用深度优先搜索,每层遍历从pos开始到末尾的元素,对于每个元素,将其加入路径,递归调用时传入相同的pos(允许重复),并更新和为sum + candidates[i]。当sum == target时,将当前路径加入结果并返回;当sum > target时,直接剪枝返回。这样就能枚举所有不重复的组合(因为通过pos参数保证了元素选取的顺序性,避免了[2,3][3,2]重复)。排序后剪枝更高效,但即使不排序,算法依然正确。

三.代码演示

class Solution { public: vector<vector<int>> ret; vector<int>path; vector<vector<int>> combinationSum(vector<int>& candidates, int target) { dfs(candidates,target,0,0); return ret; } void dfs(vector<int>& candidates,int target,int sum,int pos) { //递归终止情况 if(sum == target) { ret.push_back(path); return; } if(sum > target || pos >= candidates.size()) return; for(int i = pos;i < candidates.size();i++) { path.push_back(candidates[i]); dfs(candidates,target,sum + candidates[i],i);//因为可以选择重复的因此i不能加1 path.pop_back(); } } };

四.代码讲解

一、全局变量设计

为了实现回溯,我们定义两个成员变量

  • ret:二维向量,存储所有满足条件的组合结果。

  • path:一维向量,记录当前正在构建的组合。

二、主函数combinationSum

主函数接收候选数组candidates和目标值target,调用递归函数dfs(candidates, target, 0, 0)开始深度优先搜索,最后返回结果集ret。参数含义:

  • sum:当前路径中所有元素的和,初始为 0。

  • pos:当前可以从candidates的哪个下标开始选取元素,初始为 0。

三、递归函数dfs

递归函数dfs(candidates, target, sum, pos)的含义是:当前已经选择了若干元素(存储在path中),和为sum,接下来可以从下标pos开始继续选择元素,目标是使总和等于target。执行流程如下:

四、递归终止条件
  • 成功终止:当sum == target时,说明当前路径的和恰好等于目标值,将path的副本加入ret,然后返回。

  • 失败终止(剪枝):当sum > targetpos >= candidates.size()时,说明当前路径和已超过目标,或者没有更多元素可选,直接返回,不再继续探索。

五、递归步骤分解

使用for循环,从i = posi < candidates.size(),依次考虑每个候选元素:

  • candidates[i]加入path末尾。

  • 递归调用dfs(candidates, target, sum + candidates[i], i)。注意,这里传入的pos参数是i而不是i+1,因为同一个元素可以被无限重复选取,所以下一层仍然可以从当前下标开始,允许重复使用。

  • 递归返回后,执行回溯:将path末尾的元素弹出,以便尝试下一个元素。

六、回溯与恢复现场

由于path是全局变量,不同分支共享状态,因此必须在递归返回后手动恢复现场

七、关键细节
  • 重复选取的实现:递归调用时pos参数传入i而不是i+1,使得下一层可以继续选择当前元素,从而允许无限次重复。

  • 剪枝优化:在递归入口处检查sum > target,一旦超过则立即返回,避免无效的深度递归,提高了效率。

  • 避免重复组合:通过pos参数控制选择范围,每次只能从当前或之后的下标开始,保证了组合的无序性(不会出现[2,3][3,2]重复)。

http://www.jsqmd.com/news/735600/

相关文章:

  • 2026年专业旧房改造装修公司实力排行盘点:三室两厅两卫装修实景,公寓装修小户型装修公司,优选推荐! - 优质品牌商家
  • Figma中文界面终极指南:3分钟解锁全中文设计体验
  • AI抠图哪个软件好用?2026年最全对比指南,终于找到一款真正好用的
  • AI+行业:不是魔法,但比魔法更有趣
  • GeoAgent:基于地理相似性奖励的视觉定位强化学习模型解析
  • 第三部分-纹理与贴图——16. 高级纹理技术
  • 【2026收藏版】基于LLM的Agent构建全攻略,小白也能上手的生产级落地指南
  • 复杂室外应急保障:镜像视界无感定位,数字孪生支撑无盲区救援与态势推演
  • 2026年3月工业大风扇品牌推荐,工业大吊扇/永磁大风扇/工业风扇/工业大风扇/工业吊扇,工业大风扇实力厂家推荐 - 品牌推荐师
  • PicoLM:轻量级本地大语言模型推理引擎部署与优化指南
  • DaVinci异构计算中的RPC优化与缓存管理实践
  • java内部类的最详细详解
  • CacheSQL(四):CacheSQLClient——用一张路由表实现水平扩展
  • Meta 终止与萨马合作:因员工曝光雷朋 Meta 拍摄私密画面?
  • Visual C++运行库终极修复指南:快速解决Windows系统依赖问题
  • Spring AI 2.0 开发Java Agent智能体 - Ollama简介以及安装和使用
  • Visual C++运行库一体化解决方案:彻底解决Windows系统依赖问题的技术指南
  • 第四部分-模型与动画——18. 模型加载
  • 从零实现大语言模型推理引擎:PicoLM的极简架构与CPU部署实战
  • 内容创作团队借助 Taotoken 调用不同模型生成多样化文案
  • 小而美:快捷方式美化的极简产品设计理念
  • Silk v3音频解码器:打破微信QQ语音格式壁垒的技术实现
  • 从Windows ANI到Linux XCursor:动态光标格式转换原理与实战
  • ChatCrystal:本地化AI对话应用部署与核心架构解析
  • 第四部分-模型与动画——19. 模型动画
  • 收藏|2026年版 年龄从不是职业枷锁!35+程序员小白转型大模型完全可行
  • 图扩散Transformer在分子设计中的应用与优化
  • CacheSQL(三):双 HTTP 引擎与 SQL 查询——接口抽象的价值
  • 基于MCP协议的AI代理控制服务器:安全赋能AI操作本地系统
  • 告别双系统!保姆级教程:在Ubuntu 22.04上用Wine+PlayOnLinux搞定微信和Keil5