递归算法核心思维
很多人初次接触递归时,往往对代码的执行流程感到困惑甚至恐惧。其实理解递归的关键在于建立宏观视角:不要过度纠结函数调用自己的细节展开,而是相信函数的功能。
就像我们调用一个加法函数是为了利用它的计算能力一样,在递归中调用自身也是为了实现某个特定目标。以归并排序为例,mergesort 的功能是将无序数组变为有序。当我们调用 mergesort(left) 和 mergesort(right) 时,只需假设它们已经完成了各自部分的排序任务,剩下的工作就是合并这两个有序部分。这种'信任'是编写递归逻辑的基础,同时必须确保存在明确的递归结束条件,防止无限循环。
1. 汉诺塔
题目描述
有三根柱子 A、B、C,A 柱上有 n 个大小不同的圆盘,从小到大叠放。要求将 A 柱上的所有盘子移动到 C 柱,移动过程中大盘子不能压在小盘子上面,且每次只能移动一个盘子。
解法思路
这是一个经典的递归问题。我们可以从简单情况推导:
- n=1:直接将盘子从 A 移到 C。
- n=2:借助 B 柱,先将小盘移到 B,大盘移到 C,最后小盘移到 C。
- n>2:策略一致。将 A 上 n-1 个盘子移到 B(借助 C),将最大的盘子移到 C,再将 B 上的 n-1 个盘子移到 C(借助 A)。
核心在于将规模为 n 的问题拆解为规模为 n-1 的子问题。当规模缩减到 1 时,直接执行移动操作。
C++ 实现
class Solution {
public:
void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
dfs(A, B, C, A.size());
}
private:
void dfs(vector<int>& x, vector<int>& y, vector<int>& z, int n) {
if (n == 1) {
// 递归结束条件:x 柱中只有一个盘子,直接放到 z 柱即可
z.push_back(x.back());
x.pop_back();
return;
}
// 先将 n-1 个盘中利用 z 柱放到 y 柱上
dfs(x, z, y, n - 1);
z.(x.());
x.();
(y, x, z, n - );
}
};




