486.预测赢家

125 阅读1分钟

题目:
给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。

玩家 1 和玩家 2 轮流进行自己的回合,玩家 1 先手。开始时,两个玩家的初始分值都是 0 。每一回合,玩家从数组的任意一端取一个数字(即,nums[0] 或 nums[nums.length - 1]),取到的数字将会从数组中移除(数组长度减 1 )。玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时,游戏结束。

如果玩家 1 能成为赢家,返回 true 。如果两个玩家得分相等,同样认为玩家 1 是游戏的赢家,也返回 true 。你可以假设每个玩家的玩法都会使他的分数最大化。
算法:
方法一:动态规划 思路: dp[i][j],i表示start,j表示end, i <= j。dp[i][j]表示nums元素取值范围为[i:j]时,我方最大分数(求和不好求,那就求分差喽)。先-后手最大分差。
状态转移方程:

dp[i][j] = max(nums[i] - dp[i + 1][j], dp[i][j - 1] - num[j]) 对nums求和得到sum,如果dp[i][j] >= 0,则我方能赢.

func PredictTheWinner(nums []int) bool {
	n := len(nums)
	dp := make([][]int, n)
	for i := range dp {
		dp[i] = make([]int, n)
		dp[i][i] = nums[i]
	}

	for i := n - 1; i >= 0; i -- {
		for j := i + 1; j < n; j ++ {
			dp[i][j] = max(nums[i] - dp[i + 1][j], nums[j] - dp[i][j - 1])
		}
	}
	return dp[0][n - 1] >= 0
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

方法二:递归

func PredictTheWinner(nums []int) bool {
	return total(nums, 0, len(nums) -1, 1) >= 0
}

// 从start,计算到end,统计分数差,先手turn=1,加分,后手turn=-1,扣分
func total(nums []int, start, end, turn int) int {
	if start == end {
		return nums[start] * turn
	}
	startScore := nums[start] + total(nums, start + 1, end, -1)
	startEnd := nums[end] + total(nums, start, end - 1, -1)
	return max(startScore, startEnd) * turn

}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}