news 2026/4/28 23:07:40

回溯算法详解:从原理到实战(C++代码实现)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
回溯算法详解:从原理到实战(C++代码实现)


前言

回溯算法是基于**深度优先搜索(DFS)**的经典算法思想,核心是“尝试-回退”,通过遍历解空间找到所有符合条件的解。它广泛应用于排列、组合、子集等问题,本文将结合LeetCode经典例题,用C++实现回溯算法,讲解核心思路与实战技巧。

一、回溯算法通用框架(C++)

回溯的核心是递归函数中完成选择-递归-撤销选择的循环,C++通用框架模板如下:

cpp

#include <vector>
using namespace std;

vector<vector<int>> result; // 存储最终结果

void backtrack(/* 路径,选择列表,其他参数 */) {
if (/* 结束条件 */) {
result.push_back(/* 当前路径 */);
return;
}
for (/* 遍历选择列表 */) {
// 做选择
// 递归
backtrack(/* 新的路径和选择列表 */);
// 撤销选择
}
}


二、经典例题C++实现

2.1 组合问题(LeetCode 77. 组合)

题目:给定 n 和 k ,返回 [1,n] 中所有 k 个数的组合。
思路:用 start 控制选择起点避免重复,路径长度等于 k 时保存结果,同时剪枝优化。

cpp

#include <vector>
using namespace std;

class Solution {
private:
vector<vector<int>> res;
vector<int> path;
void backtrack(int n, int k, int start) {
if (path.size() == k) {
res.push_back(path);
return;
}
// 剪枝:剩余数字不足时直接退出
for (int i = start; i <= n - (k - path.size()) + 1; ++i) {
path.push_back(i); // 做选择
backtrack(n, k, i + 1); // 递归
path.pop_back(); // 撤销选择
}
}
public:
vector<vector<int>> combine(int n, int k) {
backtrack(n, k, 1);
return res;
}
};


2.2 全排列问题(LeetCode 46. 全排列)

题目:给定无重复数字的数组 nums ,返回所有全排列。
思路:用 used 数组标记已选元素,路径长度等于数组长度时保存结果。

cpp

#include <vector>
using namespace std;

class Solution {
private:
vector<vector<int>> res;
vector<int> path;
void backtrack(vector<int>& nums, vector<bool>& used) {
if (path.size() == nums.size()) {
res.push_back(path);
return;
}
for (int i = 0; i < nums.size(); ++i) {
if (used[i]) continue; // 跳过已选元素
used[i] = true; // 做选择
path.push_back(nums[i]);
backtrack(nums, used); // 递归
path.pop_back(); // 撤销选择
used[i] = false;
}
}
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<bool> used(nums.size(), false);
backtrack(nums, used);
return res;
}
};


2.3 子集问题(LeetCode 78. 子集)

题目:给定数组 nums ,返回所有可能的子集(幂集)。
思路:遍历过程中每一步的路径都是一个子集,直接保存,用 start 控制选择起点避免重复。

cpp

#include <vector>
using namespace std;

class Solution {
private:
vector<vector<int>> res;
vector<int> path;
void backtrack(vector<int>& nums, int start) {
res.push_back(path); // 每一步都保存子集
for (int i = start; i < nums.size(); ++i) {
path.push_back(nums[i]); // 做选择
backtrack(nums, i + 1); // 递归
path.pop_back(); // 撤销选择
}
}
public:
vector<vector<int>> subsets(vector<int>& nums) {
backtrack(nums, 0);
return res;
}
};


三、回溯算法优化技巧

1. 剪枝:提前判断当前路径是否无法得到有效解,直接跳过分支(如组合问题中 i <= n - (k - path.size()) + 1 )。
2. 状态标记:用 bool 数组/哈希表标记已使用元素,避免重复选择(如全排列的 used 数组)。
3. 排序去重:若数组含重复元素(如LeetCode 47. 全排列 II),先排序再跳过重复元素,避免生成重复解。

四、应用场景

回溯算法适用于需要穷举所有可能解的场景:

- 排列/组合/子集类问题;
- N皇后、数独等棋盘问题;
- 单词搜索、迷宫路径等搜索问题;
- 分割回文串、复原IP地址等分割问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 15:07:18

三防手持平板赋能仓库WMS系统移动作业高效率

在现代仓储物流管理中&#xff0c;WMS系统的高效运转已成为企业提升作业效率、降低出错率的关键。然而&#xff0c;传统的作业方式常因设备不匹配、环境复杂等因素&#xff0c;影响系统效能的最大化释放。 一、工业级设计&#xff0c;无惧严苛作业环境 仓储作业环境复杂&#…

作者头像 李华
网站建设 2026/4/28 7:59:53

什么是可信计算?基于可信计算的网络安全自适应防护关键技术及应用

什么是可信计算可信计算是指如果一个实体的行为总是按照预期的方式和目标进行&#xff0c;则该实体是可信的。它通过构建从硬件通电到软件运行的全程可信节点监控与保护机制&#xff0c;确保所有环节的安全可信。可信计算经历了从V1.0的容错计算、V2.0的被动可信到V3.0及新时期…

作者头像 李华
网站建设 2026/4/28 12:09:33

Flutter状态管理全解析:Provider vs Bloc vs Riverpod实战对比

一、为什么需要状态管理&#xff1f; 1.1 Flutter状态管理的挑战 在Flutter中&#xff0c;状态管理面临三大核心挑战&#xff1a; 跨组件通信&#xff1a;如何在不同层级组件间共享数据性能优化&#xff1a;如何避免不必要的重建代码可维护性&#xff1a;如何组织复杂应用的…

作者头像 李华
网站建设 2026/4/25 14:03:08

管理案例丨华恒智信助力某大型钢铁集团人力资源管理咨询服务项目——以系统性诊断与双维考核,驱动效率与效能双重提升

【客户类型】生产制造行业、钢铁冶金行业、重型制造业、跨行业多元化集团 【问题类型】组织绩效考核体系重建、跨部门协同机制优化、业绩与管理平衡发展、人力资源管理、企业管理一、项目背景&#xff1a;领军企业的绩效管理之困该集团公司是一家立足山西、辐射全国的行业巨头&…

作者头像 李华
网站建设 2026/4/25 14:04:13

基于SpringBoot的车辆报废回收系统(毕业设计项目源码+文档)

课题摘要 在机动车报废回收行业规范化、数字化升级的背景下&#xff0c;传统车辆报废回收模式存在 “流程审批繁琐、车辆溯源难、数据统计滞后、监管透明度低” 的痛点&#xff0c;难以满足车主便捷报废、企业高效运营、监管部门精准管控的需求。基于 SpringBoot 的车辆报废回收…

作者头像 李华