1、问题分析
题目链接:https://leetcode-cn.com/problems/divisor-game/
可以使用动态规划解决,具体思路就是减去每一个约数,然后查看对方是否能赢,如果对方会输,我们就选择这个状态,否则如果试过全部的约数,我们还是输,那么认命吧!!!亲,这时就是输的状态。代码我已经进行了详细的注释,理解应该没有问题,读者可以作为参考,如果看不懂(可以多看几遍),欢迎留言哦!我看到会解答一下。
2、问题解决
笔者以C++
方式解决。
#include "iostream"
using namespace std;
#include "algorithm"
#include "vector"
#include "queue"
#include "set"
#include "map"
#include "cstring"
#include "stack"
class Solution {
private:
// 定义数字最大值
const static int MAXN = 1001;
// 存储 数字 n 爱丽丝 能否赢
// 例如:dp[2] 代表 黑板上的数字为 2 时 ,爱丽丝是否能赢
// 其中各个值代表的含义为: -1 输 0 未计算 1 赢
int dp[MAXN] = { 0 };
public:
bool divisorGame(int N) {
// 递归边界
if (N == 1) {
dp[N] = -1;
return dp[N] == 1;
}
else if (N == 2) {
dp[N] = 1;
return dp[N] == 1;
}
else if (N == 3) {
dp[N] = -1;
return dp[N] == 1;
}
// 如果值已经计算过,直接返回
if (dp[N] == -1 || dp[N] == 1) {
return dp[N] == 1;
}
// divisor存放约数
vector<int> divisor;
// 计算数字 N 的约数
getDivisor(N, divisor);
for (int i = 0; i < divisor.size(); ++i) {
// 相当于将对面变成我这个状态,即如果我减去一个数之后,如果对方必输 ,那么OK嘛!
// 咱就减去这个数,如果减去所有的约数,对方依然坚挺,会赢,说明。。。认命吧!!!我们必输
if (!divisorGame(N - divisor[i])) {
dp[N] = 1;
break;
}
}
// 不是 1 说明我们输了,将状态变成输的状态
if (dp[N] != 1) {
dp[N] = -1;
}
// 返回是否赢
return dp[N] == 1;
}
/**
* 计算约数
* @param index
* @param divisor
*/
void getDivisor(int index, vector<int> &divisor) {
divisor.clear();
for (int i = 1; i <= index / 2; ++i) {
if (index % i == 0) {
divisor.push_back(i);
}
}
}
};
int main() {
int N = 81;
Solution *pSolution = new Solution;
bool b = pSolution->divisorGame(N);
cout << b << endl;
system("pause");
return 0;
}
运行结果
有点菜,有时间再优化一下。
有个更骚的解法。
class Solution {
public:
bool divisorGame(int N) {
return (N+1) & 1;
}
};
运行结果
3、总结
书上的代码直接运行绝大部分是对的,但是总有一些软件的更新使得作者无能为力。之前的API是对的,但是之后就废弃了或修改了是常有的事。所以我们需要跟踪源代码。这只是一个小小的问题,如果没有前辈的无私奉献,很难想象我们自己一天能学到多少内容。感谢各位前辈的辛勤付出,让我们少走了很多的弯路!
点个赞再走呗!欢迎留言哦!