Leetcode 1140:石子游戏 II(超详细的解法!!!)
发布日期:2021-06-29 16:06:13 浏览次数:2 分类:技术文章

本文共 2199 字,大约阅读时间需要 7 分钟。

亚历克斯和李继续他们的石子游戏。许多堆石子 排成一行,每堆都有正整数颗石子 piles[i]。游戏以谁手中的石子最多来决出胜负。

亚历克斯和李轮流进行,亚历克斯先开始。最初,M = 1

在每个玩家的回合中,该玩家可以拿走剩下的 X 堆的所有石子,其中 1 <= X <= 2M。然后,令 M = max(M, X)

游戏一直持续到所有石子都被拿走。

假设亚历克斯和李都发挥出最佳水平,返回亚历克斯可以得到的最大数量的石头。

示例:

输入:piles = [2,7,9,4,4]输出:10解释:如果亚历克斯在开始时拿走一堆石子,李拿走两堆,接着亚历克斯也拿走两堆。在这种情况下,亚历克斯可以拿到 2 + 4 + 4 = 10 颗石子。 如果亚历克斯在开始时拿走两堆石子,那么李就可以拿走剩下全部三堆石子。在这种情况下,亚历克斯可以拿到 2 + 7 = 9 颗石子。所以我们返回更大的 10。

提示:

  • 1 <= piles.length <= 100
  • 1 <= piles[i] <= 10 ^ 4

解题思路

这个问题首先我们可以想到通过dfs来做,我们定义函数 f ( i , M ) f(i,M) f(i,M),表示在piles[i:]中以[1,2*M]为取值范围可以取的最多石子数的差(看后面解释),那么

  • f ( i , M ) = m a x ( s u m ( p i l e s [ i : i + x ] ) − f ( i + x , m a x ( M , x ) ) )    ( 1 ≤ x ≤ 2 ∗ M ) f(i,M)=max(sum(piles[i:i+x])-f(i+x,max(M, x)))\ \ (1\leq x \leq 2*M) f(i,M)=max(sum(piles[i:i+x])f(i+x,max(M,x)))  (1x2M)

稍微解释一下,我们上面这个式子实际上得到的是以亚历克斯起手最后两人得到的石子数的最大差值,那么最后我们需要计算亚历克斯能有多少石子的话,我们就需要将结果加上sum(piles)然后除上2即可。

from functools import lru_cacheclass Solution:    def stoneGameII(self, piles: List[int]) -> int:        n = len(piles)        @lru_cache(None)        def dfs(d, x):            if d + 2*x >= n:                return sum(piles[d:])            res = float("-inf")            for i in range(1, 2*x+1):                res = max(res, sum(piles[d:d + i]) - dfs(d + i, max(i, x)))            return res        return (sum(piles) + dfs(0, 1))//2

我们当然可以定义函数 f ( i , M ) f(i,M) f(i,M),表示在piles[i:]中以[1,2*M]为取值范围可以取的最多石子数,那么此时的方程需要变化一下

  • f ( i , M ) = s u m ( p i l e s [ i : ] ) − m i n ( f ( i + x , m a x ( M , x ) ) )    ( 1 ≤ x ≤ 2 ∗ M ) f(i,M)=sum(piles[i:])-min(f(i+x,max(M, x)))\ \ (1\leq x \leq 2*M) f(i,M)=sum(piles[i:])min(f(i+x,max(M,x)))  (1x2M)

也就是说,我们希望亚历克斯尽可能多拿的话,那么我们就希望李少拿。亚历克斯最多拿sum(piles[i:])个石子,而李最少拿min(f(i+x,max(M, x)))个石子,最后亚历克斯实际上可以最多拿二者之差个石子。

from functools import lru_cacheclass Solution:    def stoneGameII(self, piles: List[int]) -> int:        n = len(piles)        for i in range(n - 2, -1, -1):            piles[i] += piles[i + 1]        @lru_cache(None)        def dfs(i, m):            if i + 2 * m >= n:                 return piles[i]            return piles[i] - min(dfs(i + x, max(m, x)) for x in range(1, 2 * m + 1))        return dfs(0, 1)

reference:

我将该问题的其他语言版本添加到了我的

如有问题,希望大家指出!!!

转载地址:https://coordinate.blog.csdn.net/article/details/97757641 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Leetcode 1144:递减元素使数组呈锯齿状(超详细的解法!!!)
下一篇:Leetcode 1139:最大的以 1 为边界的正方形(超详细的解法!!!)

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年05月03日 05时41分57秒