题目描述
假设现在有两只动物吃草,每次只能吃4的次幂的草,也就是1、4、16等等,现在,给你一个整数N,代表总共有多少草,两只动物,只能交替吃草,有先手和后手区别,假设动物都绝顶聪明,哪只动物先吃完草,哪只就赢,请你求出N份草时,是先手赢还是后手赢?
思路分析
因为动物绝顶聪明,因此,可以递归尝试先手吃1份时,先手能不能赢,只要能赢,因为绝顶聪明,那么先手的肯定会按照这个策略吃草,因此,结果就是先手赢。先手吃草从1、4、16依次尝试,直到接近N时,如果先手的所有可能都递归尝试完,还不能找出一种先手赢的方法,那就后手赢。
递归base case:
当草的数量降低到4以下时,可以直接出结果:
4:先手赢
3:先手拿1后手拿1先手拿1,先手赢
2:先手拿1后手拿1,后手赢
1:先手赢
0:无意义
递归函数:
递归需要想明白一个问题,那就是,当先后拿完,到后手的时候,因为两个动物都绝顶聪明嘛,因此,此时,后手拿的时候,其实,如果不考虑他之前的情况,到他的时候,其实,他就是先手拿,因此,我们只需要一种先手函数就行了,无论先手还是后手,都绝顶聪明,都会选择自己能赢的策略,因此是同一个递归函数。还有,如果后手返回的是后手赢,其实,就是先手赢了。因为,后手拿的时候,结果是后手赢,对于后手来说,此时他是先手,拿他的后手赢了,其实不就是另一个动物赢了嘛,另一个就是先手,一共就他俩玩。
代码
public static String win1(int n){
if(n<=0){
return "出的毛线题,丢雷老母嘿哟";
}
if(n<=4){
return n==2? "后手赢" : "先手赢";
}
int num=1;
while (num<=n){
//后手的后手赢了,还是先手赢
if(win1(n-num).equals("后手赢")){
return "先手赢";
}
num=num*4;
}
//所有情况都不能先手赢,再聪明绝顶也不行了,只能后手赢了
return "后手赢";
}
运行结果前20:
1:先手赢
2:后手赢
3:先手赢
4:先手赢
5:后手赢
6:先手赢
7:后手赢
8:先手赢
9:先手赢
10:后手赢
11:先手赢
12:后手赢
13:先手赢
14:先手赢
15:后手赢
16:先手赢
17:后手赢
18:先手赢
19:先手赢
20:后手赢
啥规律看明白没?怎么用打表法改呢?
打表法改进
所谓打表法,就是当你发现结果有规律时,就可以不考虑原本问题是啥,直接将规律用代码实现出来,这样的话,时间复杂度相较于原本的递归代码,直接能提升到O(1)的水平。
代码
public static String win2(int n){
if(n%5==2||n%5==0){
return "后手赢";
}else {
return "先手赢";
}
}