题目:
给你一个整数数组 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
}