目录
抢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柱,需要满足一下条件:
-
每次只能移动一个盘子
-
任何时候小盘子不能放在大盘子下边
-
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');
}
就能得到我们想要的操作过程