电话号码,组合总和
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]这个正确答案保留了机会。

相关新闻

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

终极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:37:31阅读更多 →
2026年Java后端面试技能图谱:MySQL索引、JVM与Redis深度解析

2026年Java后端面试技能图谱:MySQL索引、JVM与Redis深度解析

最近在技术圈里流传着一个让人焦虑的声音:"Java后端是不是都要失业了?" 随着AI和大模型的快速发展,很多开发者开始担心自己的技术栈会不会被淘汰。特别是看到一些新兴语言和框架的崛起,加上招聘市场的变化,这…

2026/7/25 13:37:31阅读更多 →
电梯故障诊断工具本地部署与验证指南

电梯故障诊断工具本地部署与验证指南

这次我们来看一个电梯维修相关的技术项目,重点不是复杂的电梯原理,而是如何通过本地化部署的工具或模型,辅助电梯故障的快速诊断和恢复。如果你关心电梯维保的自动化、故障预测、或者本地部署的硬件门槛、批量任务处理能力,这篇文…

2026/7/25 13:37:31阅读更多 →
NLP技术产业化实战:五大领域落地与工程优化

NLP技术产业化实战:五大领域落地与工程优化

1. 项目背景与核心价值2025年的自然语言处理技术正在经历从实验室走向产业化的关键转折期。作为一名在NLP领域深耕多年的技术从业者,我观察到当前行业面临的最大挑战不是技术本身的突破,而是如何将前沿算法真正落地到实际业务场景中。这个项目正是为了解…

2026/7/25 15:03:51阅读更多 →
人力发电机DIY:从原理到实践,探索应急电源的可行性与极限

人力发电机DIY:从原理到实践,探索应急电源的可行性与极限

这次我们来看一个关于“搞笑视频人工发电机”的项目。这个标题本身更像是一个网络梗或创意视频的标题,描述了一种荒诞的、将人力发电机与电动车结合的“解决方案”。从技术博客的角度,我们可以将其拆解为一个有趣的、探讨“人力发电”与“应急能源”概念…

2026/7/25 15:03:51阅读更多 →
智能优化算法在彩色图像多阈值分割中的应用实践

智能优化算法在彩色图像多阈值分割中的应用实践

1. 项目概述 在计算机视觉和图像处理领域,图像分割一直是个经典而富有挑战性的任务。其中,阈值分割作为最基础也最实用的方法之一,其核心问题在于如何选择最优的阈值。传统方法在处理彩色图像时往往力不从心,而智能优化算法的引入…

2026/7/25 15:03:51阅读更多 →
OpenClaw架构:AI工程化开发的三层设计实践

OpenClaw架构:AI工程化开发的三层设计实践

1. OpenClaw架构设计哲学概述OpenClaw架构代表了一种将复杂AI工程问题系统化分解的思维框架。这套方法论的核心在于通过"Prompt层-Harness层-工程层"的三级抽象,将原本混沌的AI应用开发过程转化为可标准化、可复用的工程实践。我在多个工业级AI项目中验证…

2026/7/25 15:03:51阅读更多 →
AI大模型迭代加速:技术驱动、市场博弈与开发者应对策略

AI大模型迭代加速:技术驱动、市场博弈与开发者应对策略

最近在技术社区和行业新闻中,AI大模型“竞速跑”和“迭代加速”成了高频词。无论是百度、阿里等大厂密集发布新版本,还是开发者社区里关于模型微调、本地部署的讨论热度,都指向一个事实:大模型的进化速度远超预期。对于开发者而言…

2026/7/25 15:03:50阅读更多 →
猫抓浏览器扩展:网页媒体资源嗅探的终极解决方案

猫抓浏览器扩展:网页媒体资源嗅探的终极解决方案

猫抓浏览器扩展:网页媒体资源嗅探的终极解决方案 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否曾遇到过这样的困扰&#xff1a…

2026/7/25 15:01:50阅读更多 →
Go语言静态资源打包方案对比与实践指南

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

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

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

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

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

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

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

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

2026/7/25 1:01:14阅读更多 →
突破文档下载限制:kill-doc让你看到的都能保存

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

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

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

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

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

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

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

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

2026/7/25 0:01:16阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/24 23:01:03阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/24 19:00:40阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/24 19:00:40阅读更多 →