leetcode
leetcode 1301 ~ 1350
石子游戏 III

石子游戏 III

难度:

标签:

题目描述

代码结果

运行时间: 279 ms, 内存: 19.7 MB


/*
 * 思路:我们使用动态规划和Java Stream来简化代码。使用一个dp数组来记录从当前索引到末尾的最大得分。
 */
import java.util.Arrays;

public class StoneGameIIIStream {
    public String stoneGameIII(int[] stoneValue) {
        int n = stoneValue.length;
        int[] dp = new int[n + 1];
        Arrays.fill(dp, Integer.MIN_VALUE);
        dp[n] = 0;
        for (int i = n - 1; i >= 0; i--) {
            int takeOne = stoneValue[i] - dp[i + 1];
            int takeTwo = (i + 1 < n) ? stoneValue[i] + stoneValue[i + 1] - dp[i + 2] : Integer.MIN_VALUE;
            int takeThree = (i + 2 < n) ? stoneValue[i] + stoneValue[i + 1] + stoneValue[i + 2] - dp[i + 3] : Integer.MIN_VALUE;
            dp[i] = Math.max(takeOne, Math.max(takeTwo, takeThree));
        }
        int aliceScore = dp[0];
        int totalScore = Arrays.stream(stoneValue).sum();
        int bobScore = totalScore - aliceScore;
        return aliceScore > bobScore ? "Alice" : aliceScore < bobScore ? "Bob" : "Tie";
    }
}

解释

方法:

该题解采用动态规划的思路。定义dp[i]为从第i个石子开始到最后一个石子结束时,当前玩家与对手的分数差的最大值。从后向前计算dp数组,每次计算考虑取1, 2, 或3堆石子的情况,选择能使当前分数最大化的方案。dp数组使用滚动数组优化空间复杂度,最终比较dp[0]与对手的分数差,以判断赢家。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
题解中提到的动态规划数组dp[i]代表当前玩家与对手的分数差的最大值,如何从这个定义出发确保两个玩家都采取最优策略?
动态规划的核心在于每个玩家都假设对方会采取对自己最不利的策略。在计算dp[i]时,我们假设从i开始,当前玩家选择了最优的策略,即尽可能增加自己的得分并减少对手的得分。dp[i]计算反映的是在玩家和对手都采取最优策略时的得分差。因此,每个dp[i]的计算都是基于对手对其后续选择的最优反应,这样通过逐步递推,确保了两个玩家都在采取最优策略。
🦆
你们如何确定动态规划的转移方程是s减去min(dp),这里的min(dp)代表了什么意义?
在这个问题中,s表示从当前石子i到最后一个石子的总分。min(dp)表示在当前玩家取了一定数量石子后,对手面对的三种情况中最小的分数差。这样,s - min(dp)实际上是计算在对手面对最坏情况下,当前玩家能够获得的最大分数差。转移方程中的min(dp)代表的是对手面对最优选择时的情况,确保当前玩家考虑到对手也会采取最优策略。
🦆
在题解的最后比较`dp[0] > s - dp[0]`来决定获胜者,这种方法是否有可能因为累加过程中的数值溢出而导致结果错误?
在Python中,整数类型是动态的,可以扩展到很大的数值而不会发生传统意义上的溢出。因此,在累加过程中不会导致数值溢出错误。此外,这种比较方法是数学上正确的,因为它直接比较了当前玩家和对手的分数差。只要分数的计算正确,这种方法就能正确反映谁是获胜者。
🦆
为什么在计算每个位置的最优解时,只需要考虑取1, 2, 或3堆石子的情况,而不是更多堆?
这个问题的设定可能来源于游戏规则的限制,通常在类似的石子游戏中,每次只允许玩家从连续的堆中取走一定数量的石子,并且这个数量有上限。如果题目规定了每次最多取3堆,那么动态规划的状态转移只需要考虑这三种情况。这是基于题目设定的限制,并不是算法本身的限制。如果游戏规则允许取更多堆,那么状态转移方程将需要相应调整以包含更多的情况。

相关问题