java 汉诺塔问题 递归
作者:互联网
题目链接
https://leetcode-cn.com/problems/hanota-lcci/
题目介绍
面试题 08.06. 汉诺塔问题
在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。
请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。
你需要原地修改栈。
示例1:
输入:A = [2, 1, 0], B = [], C = []
输出:C = [2, 1, 0]
解题思路
其实汉诺塔问题,就是一个递归问题。
递归的思想很重要,假如把这个问题分解成一个很小的问题,我该怎么做。那么,如果小问题能解决,那么这个问题在哪个地方进行了复杂化
因为无论是大问题还是小问题,它们往往共享着同一个本质内核,而那往往也是解决问题的关键。
A:1个。你会如何做?直接拿过去,很简单!
A:2个。复杂点了,刚刚我们已经解决了一个了,那我们能不能把这个问题转换为1个呢?把A的一个拿到B上,那么问题就迎刃而解了。
A:3个。更复杂了,那我们能不能也像之前一样,把A变成1个呢?把A上面2个拿到B上,那么A不就剩下1个了。再把B上的两个拿过去不就结束了。(可以类比一下A:2个的情况,只是变成了B到C,A是过渡的柱子)
class Solution {
public void hano(int n,List<Integer> A, List<Integer> B, List<Integer> C) {
// 基例 A上只有一个
if (n == 1) {
C.add(A.remove(A.size() - 1)); // A别忘了清空
return; //不返回值,但是会中断下面进程
} else {
hano(n-1,A,C,B);
hano(1,A,B,C);
hano(n-1,B,A,C);
}
}
public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
hano(A.size(),A,B,C);
}
}
最优解
其实很多时候,想要有本质上的突破,应该回到最初的地方,换个角度思考,再一次从山脚重新出发,其实这个问题不就是让我把A里的全给C嘛!很简单!
class Solution {
public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
for (Integer i:A) {
C.add(i);
}
}
}
拓展提升
其实很多时候学算法,但算法又是什么,算法不是凭空捏造的,若算法成了纯理论,它将不复有意义,算法是为了解决实际问题而设计的,说白了,与那些数学物理的思想有什么大的区别呢?就比如这道题,数学物理和算法的区别好比是python和java解决问题一样。
既然如此,很多时候遇到新的问题,不妨联想类比一下新的思想,我一直都相信,真正好的方法绝对共通的,只是可能表达形式不一样,正是这些基础的好方法构成了林林总总的方法论。
就拿这个递归来讲,其实不就是将问题转换为最简单,我们已知的可以解决的问题吗?
数学上当你学习新的理论的时候,数学老师总会说把这个陌生的问题转换为已知的问题去解决,然后用已知的推未知的
物理当你学变速运动,你不用记很多公式,你只需要记得加速度对时间的二阶导数是位移,其他你通过积分,转换就可以出来
算法上抛开本题,还有一类题目叫做动态规划,里面会有记事本,换了个名字,其实不就是记录下来我们已知的可以解决的问题吗?
当你学的越多,你可以思考的维度就越多,而当你把这一切联系起来的时候,一切都会不同。
Simple is the best!
大家觉得我写的好,可以关注我的Github,近期会一直更新java。
https://github.com/sherlcok314159/leetcode-java/blob/main/md/hano.md
标签:柱子,java,递归,List,问题,算法,汉诺塔,hano,盘子 来源: https://blog.csdn.net/qq_50974223/article/details/114376711