算法:回溯算法
引言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; } };

相关新闻

家庭KTV音响系统选型与调试指南:从核心组件到声学优化

家庭KTV音响系统选型与调试指南:从核心组件到声学优化

家庭KTV音响系统从简单的蓝牙音箱到专业级设备,选择范围很广。山水(SANSUI) Q52S作为一款卡拉OK一体机,集成了功放、混响、无线麦克风和音箱功能,适合不想折腾复杂接线的家庭用户。但真正决定KTV体验的不仅是设备品牌,更是声学环境…

2026/10/25 15:51:45 阅读更多 →
Claude工具使用:从基础调用到生产实践

Claude工具使用:从基础调用到生产实践

1. Claude工具使用基础解析在大模型应用开发领域,Claude的Tool Use功能正在改变人机交互的方式。作为Anthropic推出的核心能力之一,它允许模型主动调用外部工具来扩展自身功能边界。与传统的API调用不同,Tool Use实现了真正的"工具自主选…

2026/10/26 9:17:27 阅读更多 →
员工远程入职,劳动合同不签纸质版真的合规吗?

员工远程入职,劳动合同不签纸质版真的合规吗?

这两年远程办公和异地用人越来越普遍,不少 HR 都遇到过同一个尴尬:offer 发出去了,人也在线上入职了,可劳动合同还躺在快递单里没寄到。有人干脆发个电子版让员工打印签字再寄回,也有人直接在微信里传个 PDF 让对方&qu…

2026/10/26 9:17:27 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/26 12:00:21 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/25 22:36:10 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/26 4:52:12 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/26 12:00:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/26 5:00:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/26 3:16:46 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 12:00:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/25 13:21:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 8:34:37 阅读更多 →