LeetCode1025:除数博弈(归纳-动态规划)
方法一:归纳法:
前人栽树,后人乘凉。
1、数字N如果是奇数,它的约数必然都是奇数;若为偶数,则其约数可奇可偶。
2、无论N初始为多大的值,游戏最终只会进行到N=2时结束,那么谁轮到N=2时谁就会赢。
3、因为爱丽丝先手,N初始若为偶数,爱丽丝则只需一直选1,使鲍勃一直面临N为奇数的情况,这样爱丽丝稳赢;
N初始若为奇数,那么爱丽丝第一次选完之后N必为偶数,那么鲍勃只需一直选1就会稳赢。
4、综述,判断N是奇数还是偶数,即可得出最终结果!
复杂度分析:
时间复杂度:O(1)
空间复杂度:O(1)
public boolean divisorGame(int N) {
return N%2==0;
}
方法二:动态规划:
分析如下:
如果我们想要知道当数字N时爱丽丝赢,就要看N-x时的情况,当N-x爱丽丝赢时,则N时爱丽丝输(相当于N时爱丽丝选X,由于N-x是鲍勃先手选所以必赢);
反之,当N-x时爱丽丝输,则N时爱丽丝必赢,由于我们知道:2爱丽丝赢,3爱丽丝输,则我们就可以由2、3推N-x、N。
状态转移方程:(初始化dp数组为false)
if(N % x == 0 && dp[N-x] == false){
dp[N] = true;
break;
}
/**
* 除数博弈
* 动态规划:定义状态、状态转移方程,初始化状态,进行输出
* @param N
* @return
*/
public boolean divisorGame(int N) {
if(N ==1){return false;}
if(N ==2){return true;}
//定义状态dp[i]:当数字N=i时爱丽丝赢或者输
boolean[] dp = new boolean[N+1];
//初始化状态
dp[2] = true;
//状态转移方程
for(int i=3;i<=N;i++){
for(int j=1;j<i;j++){
//状态转移方程
if(i%j == 0 && dp[i-j] == false){
dp[i] =true;
break;//鲍勃,爱丽丝都时最佳状态,只要有一个满足条件必选
}
}
}
return dp[N];
}