每日一题 Leetcode1690石子游戏Ⅶ

1690. 石子游戏 VII

题目描述:

石子游戏中,爱丽丝和鲍勃轮流进行自己的回合,爱丽丝先开始 。

有 n 块石子排成一排。每个玩家的回合中,可以从行中 移除 最左边的石头或最右边的石头,并获得与该行中剩余石头值之  相等的得分。当没有石头可移除时,得分较高者获胜。

鲍勃发现他总是输掉游戏(可怜的鲍勃,他总是输),所以他决定尽力 减小得分的差值 。爱丽丝的目标是最大限度地 扩大得分的差值 。

给你一个整数数组 stones ,其中 stones[i] 表示 从左边开始 的第 i 个石头的值,如果爱丽丝和鲍勃都 发挥出最佳水平 ,请返回他们 得分的差值 。

示例 1:

输入:stones = [5,3,1,4,2]
输出:6
解释:
- 爱丽丝移除2,得分5 + 3 + 1 + 4=13。游戏情况:爱丽丝=13,鲍勃=0,石子=[5,3,1,4] 。
- 鲍勃移除5。得分 3 + 1 + 4 = 8。游戏情况:爱丽丝 = 13,鲍勃 = 8 ,石子=[3,1,4] 。
- 爱丽丝移除3,得分 1 + 4 = 5 。游戏情况:爱丽丝 = 18 ,鲍勃 = 8 ,石子=[1,4] 。
- 鲍勃移除1,得分4。游戏情况:爱丽丝=18,鲍勃=12,石子=[4]。
- 爱丽丝移除4,得分0。游戏情况:爱丽丝=18 ,鲍勃=12,石子=[]。
得分的差值 18 - 12 = 6 。

示例 2:

输入:stones = [7,90,5,1,100,10,10,2]
输出:122

提示:

  • n == stones.length
  • 2 <= n <= 1000
  • 1 <= stones[i] <= 1000

思路:

1)因为Bob想降低分差,而Alice想扩大分差,其实都是一个目标,那就是自己尽量取分。
每次选择的判断就是取左边的元素获得的分与取右边的元素获得的分谁更大!创建一个函数dfs(i,j)
表示当剩下的元素为i~j时,先手与后手的得分差值。显然,在此定义下,我们要求dfs(0,n-1)。
具体地,dfs(i,j)的计算过程为:

1.如果 i>j,说明当前没有石子,返回 0;
2.否则,先手有两种选择,分别是移除 stones[i]或 stones[j],然后计算得分差值,即 a=s[j+1]−s[i+1]−dfs(i+1,j)和 b=s[j]−s[i]−dfs(i,j−1),我们取两者中的较大值作为 dfs(i,j)的返回值。

值得注意的是,学习了一个cache装饰器,用于降低递归带来的巨大时间复杂度与空间复杂度,避免重复计算。关于cache装饰器,可以看这篇:https://zhuanlan.zhihu.com/p/621769520

2)动归方法先买个坑!

代码:

class Solution:
    def stoneGameVII(self, stones: List[int]) -> int:
        #递归方法
        @cache
        def dfs(i: int, j: int) -> int:
            if i > j:
                return 0
            a = s[j + 1] - s[i + 1] - dfs(i + 1, j)
            b = s[j] - s[i] - dfs(i, j - 1)
            return max(a, b)

        s = list(accumulate(stones, initial=0))
        ans = dfs(0, len(stones) - 1)
        dfs.cache_clear()
        return ans

你可能感兴趣的:(每日刷题,leetcode,算法)