877. Stone Game

问题

有偶数堆石头(数组长度为偶数),每堆石头有一些石头(数组元素为正),石头的总数是奇数。Alex和Lee两个人轮流取石头堆,每次可以从头部或尾部取,Alex先取。

给定这样一个数组,两人都以最优策略去玩这个游戏,如果Alex一定会获胜则返回True,否则返回False

思路

做法1:因为有偶数堆,所以先玩游戏的Alex可以做到:一直取第偶数堆,或者一直取第奇数堆。石头总数是奇数,那么第偶数堆的石头总数和第奇数堆的石头总数,一定有一方大于另一方。所以Alex可以计算出哪方大来取。假设第奇数堆的石头总数大于第偶数堆的石头总数,Alex就一直取第奇数堆来获胜。所以Alex总能获胜,直接return True即可。

时间复杂度O(1),空间复杂度O(1)

做法2:也可以用dp的做法来做。由于是一个双方博弈的游戏,dp表示单方的获取价值(石头)不好做,我们定义dp为双方的获取价值的差,即“Alex比Lee多获得的价值”。

对于Alex而言,他要使得dp值最大,用dp[i][j]表示从i到j的石头堆中Alex比Lee多获得的石头数,到Alex选时要么选i要么选j,选的时候增加dp值,dp公式为\(dp[i][j] = max(piles[i] + dp[i+1][j], piles[j] + dp[i][j-1])\)

对于Lee而言,他要使得dp值最小,同样要么选i要么选j,这时的选择会减少dp值,因为是Lee选择,会使得“Alex比Lee多获得的石头数”减少。dp公式为\(dp[i][j] = min(-piles[i] + dp[i+1][j], -piles[j] + dp[i][j-1])\)

时间复杂度O(n2),空间复杂度O(n2)

做法3:事实上dp可以优化成一维数组,因为每次迭代是按dp矩阵的对角线迭代,从左方值(dp[i][j-1])或下方值(dp[i+1][j])选择。可以转为按行索引迭代(去掉列索引),dp的变化示意图如下,蓝色表示dp运算前的值,绿色代表运算dp需要使用的值,红色表示dp运算后得到的新值。从对角线开始(i等于j)不断迭代dp得到最后的红色就是最终结果。

时间复杂度O(n^2),空间复杂度O(n)

代码

做法1

class Solution(object):
    def stoneGame(self, piles):
        """
        :type piles: List[int]
        :rtype: bool
        """
        return True

做法2

class Solution(object):
    def stoneGame(self, piles):
        """
        :type piles: List[int]
        :rtype: bool
        """
        dp = [ [0 for _ in range(len(piles))] for _ in range(len(piles)) ]
        for size in range(2,len(piles)+1):
            for i in range(0,len(piles)-size+1):
                j = i+size-1
                if( size % 2 == 0):
                    dp[i][j] = max(piles[i] + dp[i+1][j], piles[j] + dp[i][j-1])
                else:
                    dp[i][j] = min(-piles[i] + dp[i+1][j], -piles[j] + dp[i][j-1])
        return dp[0][len(piles)-1] >= 0

做法3

class Solution(object):
    def stoneGame(self, piles):
        """
        :type piles: List[int]
        :rtype: bool
        """
        dp = [0]* len(piles)
        for size in range(2,len(piles)+1):
            for i in range(0,len(piles)-size+1):
                j = i+size-1
                if( size % 2 == 0):
                    dp[i] = max(piles[i] + dp[i+1], piles[j] + dp[i])
                else:
                    dp[i] = min(-piles[i] + dp[i+1], -piles[j] + dp[i])
        return dp[0] >= 0

类似题目

486. Predict the Winner

posted @ 2018-10-06 16:35  PilgrimHui  阅读(816)  评论(0编辑  收藏  举报