电话号码,组合总和
17.电话号码的字母组合力扣题目链接力扣题目链接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: vectorstringres; string s; void backtracking(const string digits,int index){//为什么用 const string而不是 string digits值传递地址省内存 if(indexdigits.size()){ res.push_back(s); return; } int ddigits[index]-0; string letletterMap[d]; for(int i0;ilet.size();i){//可以思考一下这里是0还是index s.push_back(let[i]); backtracking(digits,index1); s.pop_back(); } } vectorstring letterCombinations(string digits) { s.clear(); res.clear(); backtracking(digits,0); return res; } };为什么用const string而不是string digits如果写成string digits按值传递每次递归调用都会复制整个字符串。如果digits很长比如 10 位递归深度 10就会产生 10 份拷贝浪费时间和空间。写成const string只传递一个“别名”地址所有递归层级共用同一份原始数据零拷贝。39. 组合总和力扣题目链接class Solution { public: vectorvectorintres; vectorintpath; int sum0; void backtracking(vectorint candidates, int target,int index){ if(sumtarget){ res.push_back(path); return; } else if(sumtarget){ return; } for(int iindex;icandidates.size();i){ sumcandidates[i]; path.push_back(candidates[i]); // if(sumtarget){ // sum-candidates[i]; // path.pop_back(); // return; // }为什莫 backtracking(candidates,target,i); sum-candidates[i]; path.pop_back(); } } vectorvectorint combinationSum(vectorint candidates, int target) { backtracking(candidates,target,0); return res; } };为什莫for循环里那个判断被//了for循环是“横向”的管兄弟递归调用是“纵向”的管子孙。8和8在下一层的时候就会在开头被忽略了然后回到第一层回溯。如果数组是乱序的如[8,7,4,3]你取了8发现超标比如8已经大于target11但后面的4和3并不超标甚至8311是正确答案所以在for循环里写return会直接杀死当前整个函数导致后面的4、3根本没机会被尝试。写在for循环里并用return杀死的是整个当前函数导致for循环后面的所有i都被跳过。写在函数顶部并用return杀死的只是当前这一层递归调用即当前这个分支for循环的父层依然坚挺可以继续尝试下一个i。40.组合总和II注意先给输入的数组排个序这样只会和前一个数字相同了。我在图中将used的变化用橘黄色标注上可以看出在candidates[i] candidates[i - 1]相同的情况下used[i - 1] true说明同一树枝candidates[i - 1]使用过used[i - 1] false说明同一树层candidates[i - 1]使用过可能有的录友想为什么 used[i - 1] false 就是同一树层呢因为同一树层used[i - 1] false 才能表示当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。而 used[i - 1] true说明是进入下一层递归去下一个数所以是树枝上如图所示class Solution { public: vectorvectorintres; vectorintpath; int sum0; void backtracking(vectorint candidates, int target,int index, vectorbool used){ if(sumtarget){ res.push_back(path); return; } else if(sumtarget){ return; } for(int iindex;icandidates.size() sum candidates[i] target;i){ if (i 0 candidates[i] candidates[i - 1] used[i - 1] false) { continue; } sumcandidates[i]; path.push_back(candidates[i]); used[i]true; backtracking(candidates,target,i1,used); used[i]false; sum-candidates[i]; path.pop_back(); } } vectorvectorint combinationSum2(vectorint candidates, int target) { vectorbool used(candidates.size(), false); path.clear(); res.clear(); // 首先把给candidates排序让其相同的元素都挨在一起。 sort(candidates.begin(), candidates.end()); backtracking(candidates,target,0,used); return res; } };这里直接用startIndex来去重也是可以的 就不用used数组了。class Solution { private: vectorvectorint result; vectorint path; void backtracking(vectorint candidates, int target, int sum, int startIndex) { if (sum target) { result.push_back(path); return; } for (int i startIndex; i candidates.size() sum candidates[i] target; i) { // 要对同一树层使用过的元素进行跳过 if (i startIndex candidates[i] candidates[i - 1]) { continue; } sum candidates[i]; path.push_back(candidates[i]); backtracking(candidates, target, sum, i 1); // 和39.组合总和的区别1这里是i1每个数字在每个组合中只能使用一次 sum - candidates[i]; path.pop_back(); } } public: vectorvectorint combinationSum2(vectorint candidates, int target) { path.clear(); result.clear(); // 首先把给candidates排序让其相同的元素都挨在一起。 sort(candidates.begin(), candidates.end()); backtracking(candidates, target, 0, 0); return result; } };代码中的if条件是怎么做到“只杀横向不杀纵向”的看这句关键的判决条件cppif (i startIndex candidates[i] candidates[i - 1]) { continue; }我把这个条件拆成两个“关卡”关卡含义作用i startIndex当前尝试的这个元素不是这一层for循环的第一个元素即不是“新起点”。保护纵向如果是这一层的第一个元素i startIndex哪怕它和前一个数字相同比如递归深层里的第二个1也必须保留因为它代表了“在当前路径上使用这个重复数字”这个新方向。candidates[i] candidates[i - 1]当前元素和它前一个元素的值相等。执行横向跳过既然前一个相同值已经作为“起点”试过了所有后续可能当前这个直接跳过避免重复。3. 用具体例子验证candidates [1, 1, 2],target 3为了直观我们只看根节点第一层和它下面的第二层根节点第一层startIndex0i0第一个1i startIndex是0 0不成立保留。进入递归找到了[1,1,2]和[1,2]。i1第二个1i startIndex是1 0成立且candidates[1] candidates[0]11成立。执行continue跳过。如果这里不跳过以第二个1开头会找到[1,2]这和刚才以第一个1找到的[1,2]完全重复进入第一个1的递归内部第二层startIndex1在这一层里for循环从i1开始。i1第二个1此时i startIndex是1 1不成立所以即使candidates[1] candidates[0]11也不会被跳过。结果第二个1被成功加入路径形成了[1, 1]为后续找到[1,1,2]这个正确答案保留了机会。

相关新闻

【单片机毕业设计推荐】基于 51/STM32 单片机的室内温烟环境智能监控与安防控制系统设计,基于 51/STM32 单片机的燃气温度检测与通风报警智能装置设计(017603)

【单片机毕业设计推荐】基于 51/STM32 单片机的室内温烟环境智能监控与安防控制系统设计,基于 51/STM32 单片机的燃气温度检测与通风报警智能装置设计(017603)

文章目录20 个相关毕业设计备选题目项目研究背景摘要总体方案核心功能基础功能核心功能辅助功能技术路线项目演示关于我们项目案例源码获取温馨提示:本人主页置顶文章(点我)有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶…

2026/7/25 13:36:22 阅读更多 →
Dify实战指南:从零构建AI应用,可视化工作流与RAG技术详解

Dify实战指南:从零构建AI应用,可视化工作流与RAG技术详解

最近在尝试将AI能力集成到业务系统时,发现从零开发一个智能应用涉及模型调用、知识库管理、工作流编排等多个复杂环节,开发周期长且门槛高。Dify的出现,为开发者提供了一个可视化的AI应用构建平台,极大地简化了这一过程。本文将为…

2026/7/25 13:36:22 阅读更多 →
Android ROM解包实战指南:一站式支持10+格式的Python工具链

Android ROM解包实战指南:一站式支持10+格式的Python工具链

Android ROM解包实战指南:一站式支持10格式的Python工具链 【免费下载链接】unpackandroidrom 爬虫解包 Android ROM 项目地址: https://gitcode.com/gh_mirrors/un/unpackandroidrom Android ROM解包是开发者、逆向工程师和ROM爱好者必备的核心技能。unpack…

2026/7/25 13:36:22 阅读更多 →

最新新闻

汽车级D类功放TAS6422-Q1:高功率、高效率与负载诊断深度解析

汽车级D类功放TAS6422-Q1:高功率、高效率与负载诊断深度解析

1. 项目概述 在汽车音响系统的设计里,功率放大器一直是个让人又爱又恨的核心部件。爱的是它直接决定了最终声音的力度和清晰度,恨的是它带来的散热、功耗和空间占用问题。尤其是在今天,车载电子系统越来越复杂,从大屏主机到多声道…

2026/7/25 14:13:41 阅读更多 →
如何将B站缓存视频永久保存:完整m4s转mp4操作指南

如何将B站缓存视频永久保存:完整m4s转mp4操作指南

如何将B站缓存视频永久保存:完整m4s转mp4操作指南 【免费下载链接】m4s-converter 一个跨平台小工具,将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter m4s-converter是一款专门用于将B站…

2026/7/25 14:13:41 阅读更多 →
Agency Agents:从通用AI助手到专业AI专家团队的编程范式变革

Agency Agents:从通用AI助手到专业AI专家团队的编程范式变革

你是否曾有过这样的体验:面对一个复杂的开发任务,比如要快速搭建一个全栈应用,你打开 Claude 或 Cursor,输入“帮我写一个 React 前端和 Node.js 后端”,结果 AI 助手给你的代码虽然能用,但总觉得缺少点“灵魂”?它可能写出了一个标准的 CRUD 接口,但忽略了 API 设计的…

2026/7/25 14:13:41 阅读更多 →
DDrawCompat:让经典Windows游戏在现代系统上重获新生的兼容性神器

DDrawCompat:让经典Windows游戏在现代系统上重获新生的兼容性神器

DDrawCompat:让经典Windows游戏在现代系统上重获新生的兼容性神器 【免费下载链接】DDrawCompat DirectDraw and Direct3D 1-7 compatibility, performance and visual enhancements for Windows Vista, 7, 8, 10 and 11 项目地址: https://gitcode.com/gh_mirror…

2026/7/25 14:13:41 阅读更多 →
SMUDebugTool终极指南:解锁AMD锐龙处理器的底层调试力量

SMUDebugTool终极指南:解锁AMD锐龙处理器的底层调试力量

SMUDebugTool终极指南:解锁AMD锐龙处理器的底层调试力量 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://…

2026/7/25 14:13:41 阅读更多 →
AI代码生成实战:用Codex快速编写自动化脚本提升效率

AI代码生成实战:用Codex快速编写自动化脚本提升效率

最近在尝试自动化一些重复性工作时,你是否也遇到过这样的困境:想写个脚本处理文件,却卡在语法和逻辑上;想批量操作,又觉得学习编程门槛太高。如果你也有类似的烦恼,那么今天介绍的 Codex 可能会成为你的得力…

2026/7/25 14:12:40 阅读更多 →

日新闻

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解决您的…

2026/7/25 0:00:35 阅读更多 →
C++ string类模拟实现:从深拷贝到内存管理的完整指南

C++ string类模拟实现:从深拷贝到内存管理的完整指南

1. 项目概述:为什么我们要“手撕”string类?在C的学习道路上,尤其是从C语言过渡到C的“初阶”阶段,string类绝对是一个绕不开的核心。标准库里的std::string用起来太方便了,、find、substr,几个操作符和函数…

2026/7/25 0:00:35 阅读更多 →
三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

1. 先搞清楚“三角洲寻宝鼠”到底是什么工具从名称来看,“三角洲寻宝鼠”更像是一个资源查找或文件检索类工具,而不是游戏或娱乐软件。这类工具的核心价值在于帮助用户快速定位特定资源,比如文档、图片、压缩包或特定格式的文件。如果你经常需…

2026/7/25 0:00:35 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/25 5:08:22 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/25 5:13:53 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 18:52:18 阅读更多 →

月新闻