给定一个表示分数的非负整数数组。 玩家 1 从数组任意一端拿取一个分数,随后玩家 2 继续从剩余数
组任意一端拿取分数,然后玩家 1 拿,…… 。每次一个玩家只能拿取一个分数,分数被拿取之后不再可
取。直到没有剩余分数可取时游戏结束。最终获得分数总和最多的玩家获胜。
给定一个表示分数的数组,预测玩家1是否会成为赢家。你可以假设每个玩家的玩法都会使他的分数最
大化。
两个值的时候必然是取较大的,三个值,取一个能使自己分数和最大的,后手必然留较小的给先手,因
此先手选一个值加上该较小值最大化
static int maxScore(int[] nums, int l, int r) {
//剩下一个值,只能取该值
if (l == r) {
return nums[l];
}
int selectLeft = 0;
int selectRight = nums.length - 1;
//剩下大于两个值,先手选一边(使自己得分最高的一边),后手则选使对手得分最低的一边
if ((r - l) >= 2) {
selectLeft = nums[l] +
Math.min(maxScore(nums, l + 2, r), maxScore(nums, l + 1, r - 1));
selectRight = nums[r] +
Math.min(maxScore(nums, l + 1, r - 1), maxScore(nums, l, r - 2));
}
//剩下两个值,取较大的
if ((r - l) == 1) {
selectLeft = nums[l];
selectRight = nums[r];
}
return Math.max(selectLeft, selectRight);
}
int getScore(int[] nums, int start, int end) {
int selectLeft;
int selectRight;
int gap = end - start;
if (gap == 0) {
return nums[start];
} else if (gap == 1) {
// 此时直接取左右的值就可以
selectLeft = nums[start];
selectRight = nums[end];
} else if (gap >= 2) {
// 如果gap大于2,递归计算selectLeft和selectRight
// 计算的过程为什么用min,因为要按照对手也是最聪明的来计算。
int num = getScore(nums, start + 1, end - 1);
selectLeft = nums[start] +
min(getScore(nums, start + 2, end), num);
selectRight = nums[end] + min(num, getScore(nums, start, end - 2));
}
return max(selectLeft, selectRight);
}
bool PredictTheWinner(int[] nums) {
int sum = 0;
for (int i : nums) {
sum += i;
}
int player1 = getScore(nums, 0, nums.size() - 1);
int player2 = sum - player1;
// 如果最终两个玩家的分数相等,那么玩家 1 仍为赢家,所以是大于等于。
return player1 >= player2;
//return getScore(nums, 0, nums.size() - 1) >=0 ;
}
//差值
int getScore(int[] nums, int start, int end) {
if (end == start) {
return nums[start];
}
int selectLeft = nums[start] - getScore(nums, start + 1, end);
int selectRight = nums[end] - getScore(nums, start, end - 1);
return max(selectLeft, selectRight);
}
动态规划:使用二维数组存储差值
public boolean PredictTheWinner(int[] nums) {
int length = nums.length;
int[][] dp = new int[length][length];
for (int i = 0; i < length; i++) {
dp[i][i] = nums[i];
}
for (int i = length - 2; i >= 0; i--) {
for (int j = i + 1; j < length; j++) {
//j = i +1 因此可以优化为一维数组,下标位置相同才有值,据此推导其他的值
//Math.max(nums[i] - dp[j][j], nums[j] - dp[j - 1][j - 1]);
dp[i][j] = Math.max(nums[i] - dp[i + 1][j],
nums[j] - dp[i][j - 1]);
}
}
return dp[0][length - 1] >= 0;
}