LeetCode 877 - Stone Game (Medium)

Alex and Lee play a game with piles of stones.  There are an even number of piles arranged in a row, and each pile has a positive integer number of stones piles[i].

The objective of the game is to end with the most stones.  The total number of stones is odd, so there are no ties.

Alex and Lee take turns, with Alex starting first.  Each turn, a player takes the entire pile of stones from either the beginning or the end of the row.  This continues until there are no more piles left, at which point the person with the most stones wins.

Assuming Alex and Lee play optimally, return True if and only if Alex wins the game.

 

Example 1:

Input: piles = [5,3,4,5]
Output: true
Explanation: 
Alex starts first, and can only take the first 5 or the last 5.
Say he takes the first 5, so that the row becomes [3, 4, 5].
If Lee takes 3, then the board is [4, 5], and Alex takes 5 to win with 10 points.
If Lee takes the last 5, then the board is [3, 4], and Alex takes 4 to win with 9 points.
This demonstrated that taking the first 5 was a winning move for Alex, so we return true.

 

Constraints:

  • 2 <= piles.length <= 500
  • piles.length is even.
  • 1 <= piles[i] <= 500
  • sum(piles) is odd.

方法:dp

思路:

1 构建一个三维的dp数组。dp[i][j][0] 代表的是在piles[i:j+1]这一段的时候,先手可以得到的最大分数。dp[i][j][1]代表的是在这一段的时候,后手可以得到的最大分数。

2 转移方程

   dp[i][j][0] = max(piles[i] + dp[i+1][j][1], piles[j] + dp[i][j-1][1]) 

   dp[i][j][1] = max(dp[i+1][j][0], dp[i][j-1][0])

   这里自己之前一直没有想通的是后手的这个转移方程。dp[i][j][1]是当先手已经选完了,假设先手选的是左边的这个stone,那么这时候的后手如果要做最右选择,即在i+1到j的这堆

石头里选最右的方案,其实相当于是先手在i+1到j的石头里选。

time complexity:O(n^2) space complexity: O(n^2) 

class Solution:
    def stoneGame(self, piles: List[int]) -> bool:
        if not piles or len(piles) < 2: return True 
     
        n = len(piles)
        dp = [[[0 for _ in range(2)] for _ in range(n+1)] for _ in range(n+1)]
        
        for i in range(1, n+1):
            dp[i][i][0] = piles[i-1]
        
        for l in range(2, n+1):
            for i in range(1, n):
                j = l - 1 + i 
                if j > n: break 
                if j == i + 1:
                    dp[i][j][0] = max(piles[i-1], piles[j-1])
                    dp[i][j][1] = min(piles[i-1], piles[j-1])
                else:
                    left = dp[i+1][j][1] + piles[i-1]
                    right = dp[i][j-1][1] + piles[j-1]
                    if left > right:
                        dp[i][j][0] = left
                        dp[i][j][1] = dp[i+1][j][0]
                    else:
                        dp[i][j][0] = right 
                        dp[i][j][1] = dp[i][j-1][0]
                    
        return dp[1][n][0] > dp[1][n][1]

 

上一篇:875. 爱吃香蕉的珂珂


下一篇:Ubuntu下在PyQt设计的界面上显示图片