题目描述:1025. 除数博弈
爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。
最初,黑板上有一个数字
N
。在每个玩家的回合,玩家需要执行以下操作:
选出任一
x
,满足0 < x < N
且N % x == 0
。用
N - x
替换黑板上的数字N
。如果玩家无法执行这些操作,就会输掉游戏。
只有在爱丽丝在游戏中取得胜利时才返回
True
,否则返回false
。假设两个玩家都以最佳状态参与游戏。示例 1:
输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。示例 2:
输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。提示:
1 <= N <= 1000
刷题也没有开始刷多久,并且刷题之初也是处处碰壁,但是目前积累的不多经验告诉我,每道题在最初我们都可以选择归纳总结,枚举几个实例,看看是否存在某种规律,进而在尝试进行递推,看看是否能写出函数表达式。
废话少说 show me the code!!!
方法一(找规律)
n=1时,(0,1)区间没有1的因数,故Alice输
n=2时,(0,2)之间Alice只能选择1,此时数字变为1,根据n=1时的规律,则Bob输
n=3时,(0,3)之间Alice只能选择1,此时数字变为2,根据n=2时的规律,则Alice输
n=4时,(0,4)之间可以选择1,此时数字变为3,根据n=3时的规律,则Bob输
n=5时,(0,5)之间只能选择1,此时数字变为4,根据n=4时的规律,则Alice输
。。。。。。
枚举到此,相信各位应该能感觉的到先手人员在数字n为奇数的情况下,最后必输,反之,为偶数时必胜。
最后代码也是非常简洁
class Solution {
public:
bool divisorGame(int N) {
return N % 2 == 0;
}
};
方法二(递推)
方法二可以根据上述方法一来深入递推得到更一般的解法,首先我们假设Alice此时处在 N = K的阶段下,如若she想要赢,那么she应该合理地选择某个数使得Bob处在 N = m的阶段下,且这个阶段下的Bob必输,那么Alice必胜,若这样的数不存在,则Alice输,分析大致如此。代码如下:
class Solution {
public:
bool divisorGame(int N) {
vector<int> f(N + 5, false);
f[1] = false;
f[2] = true;
for (int i = 3; i <= N; ++i) {
for (int j = 1; j < i; ++j) {
if (i % j == 0 && !f[i - j]) {
f[i] = true;
break;
}
}
}
return f[N];
}
};
初始时刻我在纠结为什么在创建向量Vector时要给其初始化Size要多加个5,而不能直接创建Size为N大小呢?想了有一会儿,因为如果不加5的话,假使N=1,这时f[2]越界访问,报错,所以这是才知道这个加5其实没有什么实际意思,只是让容器尽量大一点,免去隐患。
尽管这道题比较简单,解法可能有很多,但是目前蒟蒻的我,还是从基础做起!也愿和各大网友在艰辛刷题的过程中共同收获欢乐,一起进步,也希望一头秀发可以常伴你我……