力扣递归题解——汉诺塔问题详解

面试题 08.06. 汉诺塔问题

此题是一道经典的递归问题
在这里插入图片描述

确定大致思路

递归的原理就是需要将问题的规模缩小,直到最简的情况,此题便是只有一个盘的情况。
动画演示思路:链接: 图解汉诺塔的故事

遵循递归的思路,由结果推过程。
首先我们看最简单的情况,就是只有一个汉诺塔。毫无疑问,只需将A处的盘挪到C即可。

然后再是两个塔的情况:
在这里插入图片描述

就是先将最后一个盘上的那个盘移动到B,再将底盘移动到C,最后将上面那个盘移动到C即可
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

再推广,解决5个汉诺塔问题,可以将上面四个盘视为一个整体,像两个盘的情况一样,先将4个盘挪到B,将红色盘挪到C,再进行一系列操作将四个盘挪到C,图解如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

至此,我们便大致分析出了递归思路:

  • 将移n个塔问题简化为将n-1个塔挪到B
  • 再将第n个盘挪到C
  • 再经过一系列操作将n-1个塔挪到C

此时,看似又有一个新问题出现了:一系列操作又是什么?
很简单,我们不需要仔细分析这一系列操作的步骤,只需关注它实现的功能即可。将n-1个盘挪到B,这个步骤是不是有些眼熟?没错,就和问题开始将A处的盘挪到C一摸一样,这个操作就是将我们原本的递归函数又调用了一遍。至此我们完全找到了递归的思路。

注意:递归问题中尤其要注意递归方法本身的含义。

  • 递归函数本身就是一个功能完善的方法,此题递归函数的作用就是解决n个塔从A移动到C的问题。
  • 即这个函数的功能就是将给定的n个盘从指定位置挪到目标位置
  • 我们通过上述分析简化了问题,让问题规模越来越小,试想一下,将盘移动到最后,是不是就是将最上面的小盘放到C?这一步的操作我们肯定会写。至此我们便完成了递归的全过程。

递归三部曲

递归终止条件

上面我们分析到简化为只有一个盘的情况,再把那一个盘挪到C,我们便解决了整个问题。
所以,我们的递归终止条件就是:只有一个盘的情况

再进一步思考,我们该如何知晓只剩一个盘的情况呢? 很简单,我们只需设置一个参数size表示需要挪动的塔的数量即可

    if(size==1){
           target.add(start.remove(start.size()-1));
           return ;
       }

确定传入参数

  • size:上面我们已经分析到,我们需要知道要移动的汉诺塔的个数
  • A B C :通过上面的过程分析,我们每次需要将塔移动到不同的柱子中,我们就自然要根据移动汉诺塔到不同的位置这一动作,用三个不同的参数表示

根据分析,我们确定最后的参数如下:

 private void remove(int size,List<Integer> start,List<Integer> auxiliary,List<Integer> target)

确定完成递归的步骤

将最底下的一个盘挪到目标位置,需要进行三个步骤:

  • 将上面n-1个盘挪到中间柱子
  • 将最后一个盘挪到目标柱子
  • 再将n-1个盘挪到目标柱子

根据上述三个步骤,挪动过程代码如下:

 //先把第一根柱子上size-1个盘移到第二根柱子上
       remove(size-1,start,target,auxiliary);
       //再把第一根柱子上的最后一个盘放到第三根柱子中
       target.add(start.remove(start.size()-1));
       remove(size-1,auxiliary,start,target);

整体代码

class Solution {
    public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
    remove(A.size(),A,B,C);
    }
    private void remove(int size,List<Integer> start,List<Integer> auxiliary,List<Integer> target){
        //递归终止条件
       if(size==1){
           target.add(start.remove(start.size()-1));
           return ;
       }
       //单层中进行的操作
       //先把第一根柱子上size-1个盘移到第二根柱子上
       remove(size-1,start,target,auxiliary);
       //再把第一根柱子上的最后一个盘放到第三根柱子中
       target.add(start.remove(start.size()-1));
       remove(size-1,auxiliary,start,target);
    }
}

在这里插入图片描述

总结:

  • 想要理清递归的思路,需要找到将问题规模化小且重复同一个动作的方法
  • 找出递归过程后,分析递归三部曲,可以更好地理清思路,写出最终的代码
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值