在汉诺塔传说,有三根柱子可以用大写字母A
, B
, C
命名,其中只有A
柱子摆放n
片圆盘(1<=n<=64)
, 若要把A
柱子上的所有圆盘转移到 C
柱子上,问最少需要移动多少次圆盘?
移动圆盘的规则如下:
昨天baidu校招一面碰到的题目,问了其他同学,基本上一面都是以基础的数据结构题目为主,现在总结一下。问题估计是经典的不能在经典了,递归解决,这个题目对于递归的理解还是比较深刻。当时问了两个问题:1,是求出移动次数;2,输出每一步移动的情况。个人感觉对这类问题,重在理解。
递归解决,具体步骤如下:
(1)设 Hanoi(n, A, B, C)
表示,把A
中的n
个圆盘,通过中间媒介B
,移动到C
。现在思考如何分解Hanoi(n, A, B, C)
:
要想把A
中的n
个圆盘,移动到C
,一定会经过什么操作?
第一步:一定会先把A
中上面的n-1
圆盘移动到B
, 这个过程中C
一定是中间媒介。
第二步:然后,把A
中剩下的最大的一个圆盘(也就是最下面那个圆盘)移动到C
。
第三步:最后,把B
中所有的n-1
过个圆盘移动到C
, 很显然,现在A
一定是中间媒介。
通过上面三个步骤,可以依次类推,子问题又形成子问题,然后递归解决(切记,重在理解,不要死记)
(2) 《数据结构教程第四版》中给出的C++代码如下:
void Hanoi(int n,char a,char b,char c)
{
if (n==1)
printf("\t将第%d个盘片从%c移动到%c\n",n,a,c);
else
{
Hanoi(n-1,a,c,b); //对应着,第一步
printf("\t将第%d个盘片从%c移动到%c\n",n,a,c); //对应着,第二步
Hanoi(n-1,b,a,c); //对应着,第三步
}
}
(3)当初始值A
中有n
个圆盘的时候,要移动多少次?结合上面的代码,不难推出:
当n = 1
时: H a n o i ( n ) = 1 Hanoi(n) = 1 Hanoi(n)=1
当n > 1
时: H a n o i ( n ) = 2 ∗ H a n o i ( n − 1 ) + 1 Hanoi(n) = 2 * Hanoi(n-1) + 1 Hanoi(n)=2∗Hanoi(n−1)+1
令 f ( n ) = H a n o i ( n ) + 1 f(n) = Hanoi(n)+1 f(n)=Hanoi(n)+1 ,带入可得: f ( n ) = 2 f ( n − 1 ) f(n)=2f(n-1) f(n)=2f(n−1),像什么?等比数列。进一步得:
f ( n ) = 2 n f(n)=2^n f(n)=2n,所以得出: H a n o i ( n ) = 2 n − 1 , n > 0 Hanoi(n) = 2^{n} - 1, n>0 Hanoi(n)=2n−1,n>0
# @Time :2018/10/13
# @Author :LiuYinxing
# 递归
class Solution:
def Hanoi(self, n, a, b, c):
if n == 1:
print('将第%d个盘片从%c移动到%c' % (n, a, c))
else:
self.Hanoi(n - 1, a, c, b) # 把 a 中最上面 n-1 个圆盘移到 b,在 a 中剩下最大的哪一个
print('将第%d个盘片从%c移动到%c' % (n, a, c)) # 把 a 中最大的那个移动到 c
self.Hanoi(n - 1, b, a, c) # 现在,把 b 中上的 n-1 个圆盘,移到 c 中
if __name__ == '__main__':
solu = Solution()
n = 4
a, b, c = 'A', 'B', 'C'
solu.Hanoi(n, a, b, c)
注意: n
不应过大,从推导公式可以看出,n = 64
时,需要的步数普通计算机已经跑不了了,别说我的古董笔记本了。
声明: 总结学习,有问题或不妥之处,可以批评指正哦。
推导参考:www.cnblogs.com/vsky/p/5014657.html