汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
后来,这个传说就演变为汉诺塔游戏,玩法如下:
- 有三根杆子A,B,C。A杆上有若干碟子
- 每次移动一块碟子,小的只能叠在大的上面
- 把所有碟子从A杆全部移到C杆上
我这边就用塔1,塔2,塔3来表示A,B,C了,这样的话更好理解!这个题目真的很有趣,递归的题目就像是有一种魔力,你越是解不出来就越想解出来。所以我们这里使用递归来实现,虽然容易绕迷糊了,但是绕通透了之后就很爽!先上源码和结果,源码里有步骤,然后我在详细的讲解一下:
/**
* 汉诺塔问题
* 第一步:
* 先把n-1从塔1移动到塔2
* 再把n从塔1移动到塔3
* 第二步:
* 把n-1从塔2移动到塔3
*/
public static void move(int n, String a, String b, String c) {
if (n == 1) {
System.out.println(a + " 移动到 " + c);
} else {
move(n - 1, a, c, b);
System.out.println(a + " 移动到 " + c);
move(n - 1, b, a, c);
}
}
public static void main(String[] args) {
move(3, "塔1", "塔2", "塔3");
}
结果:
这个解题过程分为两部分:
第一部分就是将n-1移动到塔2上去,然后塔1就只剩下了一个n了,我们再把塔1上的n移到塔3上面去。
第二部分就简单了,我们已经将最大的那个移动到了塔3上面,其余的还在塔2上面,所以我们要做的就是将在塔2上面的这部分n-1移动到塔3上面去。
这就是系统的两大部分,理论上是这样的,但是我们无法直接从谁移动到谁,我们要按照规则来,所以我们用递归,在如上的结果中我们可以发现由三部分组成,这是一个由3个盘组成的汉诺塔,第一方框中的过程就是从将n-1从塔1移动到塔2的过程,然后第二个方框就是将塔1上剩下的n移动到塔3的过程,最后一个方框就是将塔2上的n-1个盘移动到塔3的一个递归过程。
当 n = 64时,也就是有 64 个盘子的时候,如果每秒移动一个盘子,大约需要 1.8×1019秒…那个时候地球会毁灭吗?
也许会,也许不会。
然后力扣上也有一道类似的题目,我们粘过来对比学习一下。
题目要求:
在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。
请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。
你需要原地修改栈。
示例1:
输入:A = [2, 1, 0], B = [], C = []
输出:C = [2, 1, 0]
示例2:
输入:A = [1, 0], B = [], C = []
输出:C = [1, 0]
代码实现:
class Solution {
public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
move(A.size(),A,B,C);
}
public static void move(int n, List<Integer> a, List<Integer> b, List<Integer> c) {
//当盘子都移动空了之后停止递归
if (n <= 0) {
return ;
} else {
move(n - 1, a, c, b);
//此时将 A 底下的那块最大的圆盘移到 C
c.add(a.remove(a.size()-1));
move(n - 1, b, a, c);
}
}
}
这个与上面那个没有太多区别,只是表示形式不一样而已,我们第一个表示的是移动过程,而第二个是只要结果,并不要求移动过程,但是本质都是一样的。
好了,关于汉诺塔的问题就到这里吧,谢谢!
汉诺塔小游戏: http://www.hannuota.cn/