基础算法之递归——抢5游戏及汉诺塔问题

目录

抢5游戏

汉诺塔问题


抢5游戏

两个人先从【数字1或2】中选择一个,然后,另一个人在这个基础上选择加1或者加2,正好加到5为止,如果是你怎么能保证这个游戏必赢呢?

这个问题很简单,我们把各种情况列出来,总能找到答案,因为一共就只有五个数字。

那换一个数字呢,比如20,你会发现,从递推的角度去思考很难得出答案,我先说2 然后...后面有非常多中情况 ,规则虽然很简单,但是这个思路确实不太行得通。此时递归的思路就来了,递归的思路是这个样子的:

如果我想要最后必定喊出20,那么对手就需要喊出18或19。

想要对手只能喊18或19,我就需要喊出17。

我想要喊出17,对手就必须喊出15或16.

想要对手喊出15或16,我就需要喊出14.......不难发现,我必须喊出来的数之间都相差3.

这个思想就是一个递归的思想,递归的思想有两个明显的妙用,

第一是,只要解决了上一步的问题就能解决下一步的问题,一依次类推就能解决全部的问题。

第二是,推导的过程是相同的,是可以复制的

但是,使用递归一定要注意,过程相同,但必须要有结束条件。

众所周知,做简单而重复的事情,是计算机最擅长的,那我们写一段代码来解决。

    /**
     * 使用递归的方法来完成抢五游戏的必胜
     * @param target 需要喊出的数字
     * @param res  需要喊的数字列表
     * @return  需要喊的数字列表
     */
    public static List<Integer> getFive(int target,List<Integer> res){
        if (target > 0){
            res.add(target);
            getFive(target - 3,res);
        }
        return res;
    }

调用一下

public static void main(String[] args) {
    List<Integer> result = getFive(25, new ArrayList<>());
    System.out.println(result);
}

就得到如下结果:

汉诺塔问题

传说越南河内有一个寺庙,寺庙里有三根柱子,憎侣之间传言如果按照某个规定将64个盘子全部移动另外的柱子上,世界末日也就到了。事实证明,如果僧侣每一秒移动一个,大概需要5800亿年,当然这只是一个传说,这也是汉诺塔(Hanoi就是河内的意思)。

汉诺塔问题的描述:有三个柱子A、B、C,现在有n个盘子,需要从A柱转移到C柱,需要满足一下条件:

  1. 每次只能移动一个盘子

  2. 任何时候小盘子不能放在大盘子下边

  3. B柱可以用来临时存放盘子,但是依然要满足小盘子不能放在大盘子下边的条件

其实,这个游戏我们小时候都玩过,如果只有三个盘子这个游戏是很简单的,但是盘子数量一旦多起来就不是很好处理了,但是如果我们逆向思考,用递归来解决,就很简单了。

假设我们要移动n个盘子到目标柱子上。那么是不是可以将n个盘子看做两部分,上面的n-1个盘子和最下面的第n个盘子。

那么我们需要将上面的n-1个盘子先移动到临时柱子上,然后将第n个盘子移动到目标柱子上,最后再将上面的n-1个盘子移动到目标柱子上就可以了。而上面的n-1个盘子也是样的操作。

有了思路,我们就可以用如下代码来完成。

   /**
     * 使用递归的方法来完成汉诺塔问题
     * @param num 要移动的盘子数量
     * @param from 起始柱子
     * @param temp 临时柱子
     * @param target 目标柱子
     */
    public static void hanoi(int num,char from,char temp,char target){
        //如果只需要移动一个盘子了,就直接移动到目标柱子
        if (num == 1){
            System.out.println("将第【"+ num +"】个盘子从【"+ from +"】移动到【"+ target +"】");
        } else {
            //num-1个盘子移动到临时柱子
            hanoi(num-1,from,target,temp);
            //将第num个盘子直接移动到目标柱子
            System.out.println("将第【"+ num +"】个盘子从【"+ from +"】移动到【"+ target +"】");
            //将num-1个盘子从临时柱子移动到目标柱子
            hanoi(num-1,temp,from,target);
        }
    }

调用一下:

public static void main(String[] args) {
    hanoi(3,'A','B','C');
}

就能得到我们想要的操作过程

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值