C++ 递归、搜索与回溯
1. 汉诺塔问题
题目来源:
LeetCode 面试题 08.06. 汉诺塔问题
题目描述: 有三根柱子 A、B、C,初始时 A 柱上有 n 个大小不同的盘子,按从大到小的顺序叠放。要求将所有盘子移动到 C 柱上,移动过程中需遵守以下规则:
- 每次只能移动一个盘子;
- 大盘子不能放在小盘子上面。
算法原理(递归):
思路
汉诺塔是递归教学的经典案例。理解它的关键在于化繁为简,从最基础的情况入手。
- 当 n=1 时:只有一个盘子,直接将其从 A 移到 C 即可。
- 当 n=2 时:需要借助辅助柱 B。先将 1 号盘子移到 B,再将 2 号盘子移到 C,最后将 1 号盘子从 B 移到 C。共需 3 步。
- 当 n>2 时:策略保持一致。我们可以将 A 柱上的 n 个盘子视为两部分:最底下的最大盘子和上面的 n-1 个盘子。
- 将 A 柱上的上面 n-1 个盘子移动到 B 柱(借助 C 作为中转);
- 将 A 柱上最大的盘子直接移动到 C 柱;
- 将 B 柱上的 n-1 个盘子移动到 C 柱(借助 A 作为中转)。
这样,规模为 n 的问题就被拆解成了两个规模为 n-1 的子问题和一个单步操作。只要解决了 n-1 的情况,n 的情况也就迎刃而解了。
算法流程
设计递归函数 dfs(vector<int>& A, vector<int>& B, vector<int>& C, int n),其中 A 为源柱,C 为目标柱,B 为辅助柱。
- 终止条件:如果当前盘子数 n=1,直接将 A 栈顶元素弹出并压入 C 栈,返回。
- 递归步骤:
- 调用
dfs(A, C, B, n-1):将 A 上的 n-1 个盘子移至 B。 - 执行移动:将 A 栈顶元素弹出并压入 C。
- 调用
dfs(B, A, C, n-1):将 B 上的 n-1 个盘子移至 C。
- 调用
解法代码(C++)
class Solution {
public:
// 递归辅助函数:将 n 个盘子从 A 移动到 C,B 作为辅助
void dfs(vector<int>& A, vector<int>& B, vector<int>& C, int n) {
if (n == 1) {
// 基础情况:只剩一个盘子,直接移动
C.push_back(A.back());
A.pop_back();
return;
}
(A, C, B, n - );
C.(A.());
A.();
(B, A, C, n - );
}
{
n = A.();
(A, B, C, n);
}
};


