Leetcode-877. 石子游戏 486. 预测赢家 (动态规划) -python

题目

  1. 亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。
    游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。
    亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。
    假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 true ,当李赢得比赛时返回 false 。
    链接:https://leetcode-cn.com/problems/stone-game/
  1. 给定一个表示分数的非负整数数组。 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端拿取分数,然后玩家1拿,……。每次一个玩家只能拿取一个分数,分数被拿取之后不再可取。直到没有剩余分数可取时游戏结束。最终获得分数总和最多的玩家获胜。
    给定一个表示分数的数组,预测玩家1是否会成为赢家。你可以假设每个玩家的玩法都会使他的分数最大化。
    链接:https://leetcode-cn.com/problems/predict-the-winner/

Example:

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

思路及代码

DP

  • dp[i,j] = nums[i], if i == j
  • dp[i,j] = max(nums[i], nums[j]), if i+1 == j
  • dp[i,j] = max(nums[i] + min(dp[i+2, j], dp[i+1, j-1]), nums[j] + min(dp[i, j-2], dp[i+1, j-1]))
  • 解释:nums[i] + min(dp[i+2, j], dp[i+1, j-1])表示在数组i到j中,如果先手拿i,后手可以在i+1和j中选,而min(dp[i+2, j], dp[i+1, j-1])表示当后手拿走一个后,剩下的是让先手能拿到的最少分数的。
  • 同理nums[j] + min(dp[i, j-2], dp[i+1, j-1])表示先手拿j,后手挑后剩一个能让先手得到最少分数的选择。
class Solution:
    def PredictTheWinner(self, nums: List[int]) -> bool:
        cache = {}
        
        def score(i, j):
            if (i,j) in cache:
                return cache[i,j]
            if i == j:
                cache[i,j] = nums[i]
                return cache[i,j]
            if i+1 == j:
                cache[i,j] = max(nums[i],nums[j])
                return cache[i,j]
            cache[i,j] = max(nums[i] + min(score(i+2, j), score(i+1, j-1)),
                            nums[j] + min(score(i+1, j-1), score(i, j-2)))
            return cache[i,j]
        
        fir = score(0, len(nums)-1)
        sec = sum(nums) - fir
        return fir >= sec

877

该题始终先手会获胜。

复杂度

T = O ( n 2 ) T = O(n^2) T=O(n2)
S = O ( n 2 ) S = O(n^2) S=O(n2)

你可能感兴趣的:(Leetcode)