发布时间:2026/7/25 13:37:27
电话号码,组合总和 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]这个正确答案保留了机会。

相关新闻

2026/7/25 13:37:26

终极Obsidian导出指南:3步解锁你的知识库迁移自由

终极Obsidian导出指南:3步解锁你的知识库迁移自由 【免费下载链接】obsidian-export Rust library and CLI to export an Obsidian vault to regular Markdown 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-export 你是否曾因Obsidian笔记在其他平…

2026/7/25 13:32:26

LLM强化学习算法解析:PPO与DPO原理与实践

1. 从零理解LLM强化学习算法作为一名长期在NLP和强化学习交叉领域摸爬滚打的从业者,我发现很多刚接触大语言模型(LLM)强化学习的朋友,面对PPO、DPO这些缩写时总是一头雾水。今天我就用最直白的语言,带大家拆解这些算法…

2026/7/25 13:32:26

GPT-5.5 Instant免费体验指南:情商优化AI对话模型测试与集成

这次我们来看一个关于 ChatGPT 模型更新的消息。根据网络信息,一个名为“GPT-5.5 Instant”的版本即将更新,并计划从明天开始提供免费使用。这听起来像是一个在原有 GPT 模型基础上,特别强调“情商”或对话体验优化的迭代。对于长期关注 AI 对…

2026/7/25 14:57:34

C++ 程序从编写到可执行:完整的编译链接过程详解

C 程序从编写到可执行:完整的编译链接过程详解一、引言:从源代码到二进制一个 C 程序从文本形式的源代码到能够运行的二进制可执行文件,需要经历四个核心阶段:预处理、编译、汇编和链接。理解这个流程不仅有助于理解编译错误和链接…

2026/7/25 14:57:34

C++ std::async 使用注意事项详解:从陷阱到最佳实践

C std::async 使用注意事项详解:从陷阱到最佳实践一、引言:方便的异步工具,隐藏的陷阱std::async 是 C11 引入的高级异步接口,它一行代码就能启动异步任务并返回 std::future,极大简化了多线程编程。然而,s…

2026/7/25 14:57:34

TI SimpleLink Wi-Fi射频测试工具Radio Tool实战指南

1. 项目概述与射频测试核心价值在物联网设备开发中,无线通信的稳定性和可靠性是产品能否成功落地的基石。无论是智能家居中的传感器,还是工业现场的远程控制器,其Wi-Fi模块的射频性能直接决定了通信距离、抗干扰能力和整体用户体验。然而&…

2026/7/25 14:57:34

springbootA597D在线书籍商城系统

一、关键词在线书籍商城系统、在线书籍商城、在线书籍商城订单管理、在线书籍商城在线交易二、作品包含源码数据库万字设计文档PPT全套环境和工具资源本地部署教程三、项目技术前端技术: Html、Css、Js、Vue3.2、Element-Plus后端技术:Java、SpringBoot3…

2026/7/25 14:52:33

企业内如何通过Taotoken实现API调用的统一审计与权限管理

企业内如何通过Taotoken实现API调用统一审计与权限管理 在将大模型能力引入企业工作流的进程中,如何确保API调用的安全、合规与可控,是技术管理者面临的核心挑战。直接使用多个厂商的原生API密钥,不仅管理分散,更难以追溯使用情况…

2026/7/25 12:13:16

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/25 0:00:15

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

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

2026/7/25 0:00:15

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

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

2026/7/25 0:00:15

VHF 甚高频语音喊话系统(桥梁智能防撞场景)核心优势

一、直达船员,预警链路最短营运船舶强制标配 VHF 船载电台,属于驾驶室常态化值守设备;预警语音直接传递至驾驶人员,区别于岸上声光报警(船员经常听不到)、短信 / 小程序(船员极少主动查看&#…

2026/7/25 0:59:36

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…