Predict the Winner 预测赢家

给定一个表示分数的非负整数数组。 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端拿取分数,然后玩家1拿,……。每次一个玩家只能拿取一个分数,分数被拿取之后不再可取。直到没有剩余分数可取时游戏结束。最终获得分数总和最多的玩家获胜。

给定一个表示分数的数组,预测玩家1是否会成为赢家。你可以假设每个玩家的玩法都会使他的分数最大化。

示例 1:

输入: [1, 5, 2]
输出: False
解释: 一开始,玩家1可以从1和2中进行选择。
如果他选择2(或者1),那么玩家2可以从1(或者2)和5中进行选择。如果玩家2选择了5,那么玩家1则只剩下1(或者2)可选。
所以,玩家1的最终分数为 1 + 2 = 3,而玩家2为 5。
因此,玩家1永远不会成为赢家,返回 False。

示例 2:

输入: [1, 5, 233, 7]
输出: True
解释: 玩家1一开始选择1。然后玩家2必须从5和7中进行选择。无论玩家2选择了哪个,玩家1都可以选择233。
最终,玩家1(234分)比玩家2(12分)获得更多的分数,所以返回 True,表示玩家1可以成为赢家。

注意:

  1. 1 <= 给定的数组长度 <= 20.
  2. 数组里所有分数都为非负数且不会大于10000000。
  3. 如果最终两个玩家的分数相等,那么玩家1仍为赢家。

思路一:采用minimax算法,对玩家进行分类,如果是玩家A,则进入左分支,累加玩家A的分数,如果是玩家B,则进入右分支,累加玩家B的分数。递归的边界条件时数组为空或者数组的左边界大于右边界,这时根据玩家A累加的分数left_sum和玩家B累加的right_sum分数作对比,如果这轮是A玩家则返回left_sum>=right_sum,如果是B玩家,则返回right_sum>left_sum。在递归中如果下一个玩家返回false,那么这个玩家立马返回true。

参考代码:

class Solution {
public:
bool PredictTheWinnerCore(vector<int> nums, int left, int right, bool leftTurn,int start,int end) {
	if (start > end) {
		return false;
	}
	if (start == end) {
		if (leftTurn) {
			return left >= right;
		}
		else {
			return right > left;
		}
	}
	int leftSum = 0;
	int rightSum = 0;
	if (leftTurn) {
		for (int i = 0; i < 2; i++) {
			bool result = false;
			if (i == 0) {
				result = PredictTheWinnerCore(nums, left + nums[start], right, !leftTurn, start + 1,end);
			}
			else {
				result = PredictTheWinnerCore(nums, left + nums[end], right, !leftTurn, start, end-1);
			}
			if (result == false) {
				return true;
			}
		}
	}
	else {
		for (int i = 0; i < 2; i++) {
			bool result = false;
			if (i == 0) {
				result = PredictTheWinnerCore(nums, left , right + nums[start], !leftTurn, start + 1, end);
			}
			else {
				result = PredictTheWinnerCore(nums, left, right + nums[end], !leftTurn, start,end - 1);
			}		
			if (result == false) {
				return true;
			}
		}
	}
	return false;
}
bool PredictTheWinner(vector<int>& nums) {
	if (nums.size() == 0) {
		return true;
	}
	return PredictTheWinnerCore(nums, 0, 0, true,0,nums.size()-1);
}
};

思路二:采用动态规划的递归形式来做,定义二维数组dp,其中dp[i][j]在可选择的数组下标范围为[i,j]时,表示玩家A领先玩家B多少分,最后即返回dp[0,nums.size()-1]即使答案,那么递归方程中就已经不分玩家A和B了,每个玩家都尽量使得自己的领先分数正最大。所以递归公式为:

dp[start][end] = start == end ? nums[start] : max(nums[start] - PredictTheWinner2Core(nums, start + 1, end, dp), nums[end] - PredictTheWinner2Core(nums, start, end - 1, dp));

如果到达了边界(start==end),那么返回nums[start]即可,否则返回已选择的当前数nums[start]或者nums[end]与对手返回下一句的领先分数PredictTheWinner2Core(nums, start + 1, end, dp)或者PredictTheWinner2Core(nums, start, end - 1, dp)的最大差值。

参考代码:

class Solution {
public:
int PredictTheWinner2Core(vector<int>& nums,int start,int end, vector<vector<int>> &dp) {
	if (dp[start][end] == -1) {
		dp[start][end] = start == end ? nums[start] : max(nums[start] - PredictTheWinner2Core(nums, start + 1, end, dp), nums[end] - PredictTheWinner2Core(nums, start, end - 1, dp));
	}
	return dp[start][end];
}
bool PredictTheWinner(vector<int>& nums) {
	vector<vector<int>> dp(nums.size(), vector<int>(nums.size(), -1));
	return PredictTheWinner2Core(nums, 0, nums.size() - 1, dp)>=0;
}
};




猜你喜欢

转载自blog.csdn.net/qq_26410101/article/details/80849629
今日推荐