算法:回溯算法
引言40. 组合总和 II - 力扣LeetCode93. 复原 IP 地址 - 力扣LeetCode78. 子集 - 力扣LeetCode491. 非递减子序列 - 力扣LeetCode46. 全排列 - 力扣LeetCode47. 全排列 II - 力扣LeetCode51. N 皇后 - 力扣LeetCode代码第一题这个题目的最大难题就是去重所以我们先对于这个数组进行一个排序那么我们就可以从小到大一个一个的遍历只要当我们的和大于目标的时候我们就直接开始回溯。而且这样可以把相同的元素放在一起便于我们的去重。我们去重的方法用到了used数组只要这个元素和前面一个元素相同并且前面一个元素没有被使用过了那么就说明这两个元素已经重复。为什么是没有被使用过呢因为如果是使用过的说明这是第一次出现这个组合比如 {122}但是如果是没有使用过那么就说明我们是在回溯的过程之中那个数因为之前已经被处理过了所以被标记为了false。之所以我们不是直接用当前元素和上一个元素进行比较是因为我们是在回溯我们需要确定所有元素的情况而不是单一的一个相对为止i和i-1。class Solution { public: vectorint path; vectorvectorint res; void traversal(vectorint candidates, int target, int sum, int startIndex, vectorbool used) { if (sum target) { return; } if (sum target) { res.push_back(path); return; } for (int i startIndex; i candidates.size() sum candidates[i] target; i) { if (i 0 candidates[i] candidates[i - 1] used[i - 1] false) { continue; } used[i] true; sum candidates[i]; path.push_back(candidates[i]); traversal(candidates, target, sum, i 1, used); path.pop_back(); used[i] false; sum - candidates[i]; } } vectorvectorint combinationSum2(vectorint candidates, int target) { vectorbool used(candidates.size(), false); sort(candidates.begin(), candidates.end()); traversal(candidates, target, 0, 0, used); return res; } };第二题这一题考察的是分割字符串我们的startIndex不再是数组的字母了而是字母间的位置。我们每一次分割一段字串之后都会进行判断而我们的起点一个是startIndex终点是i这个点我们可以理解成每一个数组元素后面的那个空格比如i 0那么就对应的是第0个元素后面的那一个空格所以这也是一个左闭右闭得范围。然后我们每一次插入都要确定这个字串是符合规定得如果不符合规定那么就结束这个循环因为再往后遍历肯定也不符合。最后一定要注意我们插入得那个元素会改变整个数组得下标所以是i 2不再是i 1。class Solution { public: vectorstring res; bool isValid(const string s, int start, int end) { if (start end) { return false; } if (s[start] 0 start ! end) { return false; } int num 0; for (int i start; i end; i) { if (s[i] 9 || s[i] 0) { return false; } num num * 10 (s[i] - 0); if (num 255) { return false; } } return true; } void traversal(string s, int startIndex, int pointNum) { if (pointNum 3) { if (isValid(s, startIndex, s.size() - 1)) { res.push_back(s); } return; } for (int i startIndex; i s.size(); i) { if (isValid(s, startIndex, i)) { s.insert(s.begin() i 1, .); pointNum; traversal(s, i 2, pointNum); pointNum--; s.erase(s.begin() i 1); } else { break; } } } vectorstring restoreIpAddresses(string s) { if (s.size() 4 || s.size() 12) { return res; } traversal(s, 0, 0); return res; } };第三题这一题的主要难题就是怎么记录子集我们一般来说都是判断一个条件然后把结果放进去但是因为子集不需要任何判断的条件所以要放到最开始反而判断的作用仅仅是为了可以回溯。所以我们需要理解我们记录的意义到底是什么class Solution { public: vectorint path; vectorvectorint res; void traversal(vectorint nums, int startIndex) { res.push_back(path); if (path.size() nums.size()) { return; } for (int i startIndex; i nums.size(); i) { path.push_back(nums[i]); traversal(nums, i 1); path.pop_back(); } } vectorvectorint subsets(vectorint nums) { traversal(nums, 0); return res; } };第四题这一题的难点是我们需要对没有排序的数组进行去重所以我们不可以使用used数组了我们这里引用uset但是注意一下我们uset这个是在函数里面定义的也就是说每一层的递归都有一个新的uset。因为我们去重的目的就是每一层去重。我们这里深入了两个概念一个是层一个是树枝。层代表了这一个循环也就是取决于开始的位置也就是startIndex。可是为什么我们之前一直没有关心这个呢是因为我们之前一直都是处理树枝就是递归后的结果而这里需要的是一层一层的结果。class Solution { public: vectorint path; vectorvectorint res; void traversal(vectorint nums, int startIndex) { if (path.size() 1) { res.push_back(path); } unordered_setint uset; for (int i startIndex; i nums.size(); i) { if ((!path.empty() nums[i] path.back()) || uset.find(nums[i]) ! uset.end()) { continue; } uset.insert(nums[i]); path.push_back(nums[i]); traversal(nums, i 1); path.pop_back(); } } vectorvectorint findSubsequences(vectorint nums) { traversal(nums, 0); return res; } };第五题这是一个全排列的问题也就是说和起点没有什么关系所以我们这里和startIndex没啥关系但是因为要记录我们之前遍历了哪一些点所以我们用另外一个数组used来记录。class Solution { public: vectorint path; vectorvectorint res; void traversal(vectorint nums, vectorbool used) { if (path.size() nums.size()) { res.push_back(path); return; } for (int i 0; i nums.size(); i) { if (used[i] false) { used[i] true; path.push_back(nums[i]); traversal(nums, used); used[i] false; path.pop_back(); } else { continue; } } } vectorvectorint permute(vectorint nums) { vectorbool used(nums.size(), false); traversal(nums, used); return res; } };第六题这一题也是全排列而且还需要去重。所以我们必须要理解我们到底在哪里收集数据。我们肯定是在最后面也就是树枝的末尾接受数据但是因为是全排列所以我们还是不需要startIndex然后我们依然先排序把相同的数放在一起然后我们按照原来的去重逻辑不过还有一点要注意的是因为这个是全排列所以我们每一次都是从0开始遍历的所以不要忘记了在操作的时候要判断这个数是不是已经被记录了哦~~~class Solution { public: vectorint path; vectorvectorint res; void traversal(vectorint nums, vectorbool used) { if (path.size() nums.size()) { res.push_back(path); return; } for (int i 0; i nums.size(); i) { if (i 0 nums[i] nums[i - 1] used[i - 1] false) { continue; } if (used[i] false) { path.push_back(nums[i]); used[i] true; traversal(nums, used); path.pop_back(); used[i] false; } } } vectorvectorint permuteUnique(vectorint nums) { vectorbool used(nums.size(), false); sort(nums.begin(), nums.end()); traversal(nums, used); return res; } };第七题首先我们需要一个函数来判断我们这个点是不是符合规矩的。然后我们的落子路线是一行一行的所以我们不需要判断每一行是不是符合规矩的因为我们下棋的时候就已经保证了每一行只有一个。然后我们需要在每一行开始遍历每一列所以for。环是从0开始的但是我们路线是根据一行一行来的所以我们传递参数的时候需要记录一下当前是第几行的。这也就是N皇后的解法其实也不是很难一层一层的遍历。class Solution { public: vectorvectorstring res; bool isValid(int row, int col, vectorstring chessboard, int n) { for (int i 0; i row; i) { if (chessboard[i][col] Q) { return false; } } for (int i row - 1, j col - 1; i 0 j 0; i--, j--) { if (chessboard[i][j] Q) { return false; } } for (int i row - 1, j col 1; i 0 j n; i--, j) { if (chessboard[i][j] Q) { return false; } } return true; } void traversal(vectorstring chessboard, int row, int n) { if (row n) { res.push_back(chessboard); return; } for (int col 0; col n; col) { if (isValid(row, col, chessboard, n)) { chessboard[row][col] Q; traversal(chessboard, row 1, n); chessboard[row][col] .; } } } vectorvectorstring solveNQueens(int n) { std::vectorstd::string chessboard(n, std::string(n, .)); traversal(chessboard,0 , n); return res; } };

相关新闻

长文档知识库怎么切?通用RAG、文档解析与定制策略对比

长文档知识库怎么切?通用RAG、文档解析与定制策略对比

企业在选型AI应用开发公司时,常常把对话流畅度和模型参数规模放在首位,却很少追问一个更底层的问题:一份几十页甚至上百页的长文档进入知识库后,系统到底能不能可靠召回其中的关键信息。实际上,答案出错的根因可能分布…

2026/7/23 13:41:51阅读更多 →
C++——Function原理

C++——Function原理

众所周知,function可以封装任意类型的可调用对象,功能十分强大,这篇文章主要是想讲解一下function的工作原理。可调用对象有这么几种类型:仿函数对象、函数指针、lambda表达式... ... 即使这几种可调用对象的参数和返回值类型相同…

2026/7/23 13:41:51阅读更多 →
山进909x2收音机评测:性能与设计的完美结合

山进909x2收音机评测:性能与设计的完美结合

1. 山进909x2收音机深度评测 作为一名广播爱好者,我使用过不下20台各品牌收音机,但山进909x2确实给我留下了深刻印象。这台机器在2021年推出时就引起了收音机圈的广泛讨论,它既延续了山进909系列的经典设计,又在接收性能和人机交互…

2026/7/23 13:41:51阅读更多 →
基于YOLOv8的眼镜检测系统开发与优化实践

基于YOLOv8的眼镜检测系统开发与优化实践

1. 项目概述与核心价值眼镜检测系统是基于YOLOv8目标检测算法构建的完整解决方案,专为眼镜识别场景优化设计。这个开源项目最显著的特点是提供了从数据准备到模型部署的全流程支持,包含2900张标注好的眼镜数据集、70多种模型改进方案以及可自定义的Web前…

2026/7/23 15:04:12阅读更多 →
基于YOLO的实时火焰检测系统设计与优化

基于YOLO的实时火焰检测系统设计与优化

1. 火焰检测系统概述在工业安全、森林防火和智能监控领域,火焰检测一直是个关键课题。传统基于传感器的检测方式受限于覆盖范围和响应速度,而基于深度学习的视觉检测方案正在成为主流选择。YOLO系列作为实时目标检测的标杆算法,其最新迭代版本…

2026/7/23 15:04:12阅读更多 →
AgentLoop:异步AI智能体核心引擎的设计与实现

AgentLoop:异步AI智能体核心引擎的设计与实现

1. 项目概述:AgentLoop在nanobot-agent中的核心地位AgentLoop作为nanobot-agent框架的核心引擎,其设计理念源于现代AI助理系统对高效异步处理的需求。这个不足千行的Python模块实现了智能体最关键的"思考-行动"循环机制,其代码结构…

2026/7/23 15:04:12阅读更多 →
黑马点评实战笔记:从 Redis 基础到高并发踩坑指南

黑马点评实战笔记:从 Redis 基础到高并发踩坑指南

思维导图 #mermaid-svg-QDUtkuaHrbJDn6AV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QDUtkuaHrbJDn6AV…

2026/7/23 15:04:12阅读更多 →
千笔AI写作工具:学术论文智能辅助实战指南

千笔AI写作工具:学术论文智能辅助实战指南

1. 项目概述:千笔AI写作工具的核心定位 千笔AI写作是一款面向学术研究者的智能辅助工具,主要解决论文写作过程中的三大痛点:文献综述耗时、理论框架搭建困难、学术语言表达不专业。这个开源项目在GitHub上获得超过3.2k星标,被众多…

2026/7/23 15:04:12阅读更多 →
YOLO26改进方案:CIFusion模块在多模态与小目标检测中的应用

YOLO26改进方案:CIFusion模块在多模态与小目标检测中的应用

1. YOLO26改进方案概述在计算机视觉领域,目标检测算法的发展日新月异。YOLO系列作为实时目标检测的标杆,其最新版本YOLO26通过引入CIFusion(Channel Interaction Fusion)通道交互融合模块,在多模态融合和小目标检测场景…

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

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

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

2026/7/23 0:56:31阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

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

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

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

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

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

2026/7/23 0:56:31阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:00:28阅读更多 →
从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:28阅读更多 →
油泥处理设备哪里能买到

油泥处理设备哪里能买到

油泥处理设备哪里有?这是许多从事油田、炼化、清罐业务的从业者最关心的问题。根据河南三丰环保设备有限公司的行业经验,选购油泥处理设备的核心在于设备能否适配当地环保法规与原料特性,而非单纯看价格。该公司总经理王钦田先生指出&#xf…

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

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

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

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

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

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

2026/7/22 18:55:50阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

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

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

2026/7/22 18:55:50阅读更多 →