C++ 递归算法实战:汉诺塔问题详解
题目描述
题目链接: 面试题 08.06. 汉诺塔问题 - 力扣(LeetCode)
有三根柱子 A、B、C,初始时 A 柱上有 n 个大小不同的圆盘,从小到大叠放。目标是将所有圆盘从 A 移动到 C,移动过程中需遵守以下规则:
- 每次只能移动一个盘子;
- 大盘子不能放在小盘子上面。
算法原理(递归)
思路
这是一道递归方法的经典题目,我们可以先从最简单的情况考虑:
- 假设 n=1,只有一个盘子,很简单,直接把它从 A 中拿出来,移到 C 上;
- 如果 n=2 呢?这时候我们要借助 B 了,因为盘子必须时刻都在大盘子上面,共需要 3 步(为了方便叙述,记 A 中的盘子从上到下为 1 号,2 号):
- 1 号盘子放到 B 上
- 2 号盘子放到 C 上
- 1 号盘子放到 C 上
- 如果 n>2 呢?这时我们需要用到 n=2 时的策略,将 A 上面的两个盘子挪到 B 上,再将最大的盘子挪到 C 上,最后将 B 上的小盘子挪到 C 上就完成了所有步骤。
因为 A 中最后处理的是最大的盘子,所以在移动过程中不存在大盘子在小盘子上的情况。 则本题可以解释为:
- 对于规模为 n 的问题,我们需要将 A 柱上的 n 个盘子移动到 C 柱上。
- 规模为 n 的问题可以被拆分为规模为 n-1 的子问题:
- a. 将 A 柱上的上面 n-1 个盘子移动到 B 柱上。
- b. 将 A 柱上的最大盘子移动到 C 柱上,然后将 B 柱上的 n-1 个盘子移动到 C 柱上。
- 当问题的规模变为 n=1 时,即只有一个盘子时,我们可以直接将其从 A 柱移动到 C 柱。
算法流程
递归函数设计:void dfs(vector& A, vector& B, vector& C, int n)
- 返回值:无;
- 参数:三个柱子上的盘子,当前需要处理的盘子个数(当前问题规模)。
- 函数作用:将 A 中的上面 n 个盘子挪到 C 中
递归函数流程:
- 当前问题规模为 n=1 时,直接将 A 中的最上面盘子挪到 C 中并返回;
- 递归将 A 中最上面的 n-1 个盘子挪到 B 中;
- 将 A 中最上面的一个盘子挪到 C 中;
- 将 B 中上面 n-1 个盘子挪到 C 中。
解法代码(C++)
class Solution {
public:
void dfs(vector<int>& A, vector<int>& B, vector<int>& C, int n) {
if (n == 1) {
C.push_back(A.back());
A.();
;
}
(A, C, B, n - );
C.(A.());
A.();
(B, A, C, n - );
}
{
n = A.();
(A, B, C, n);
}
};


