石子游戏 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]代表当前玩家与对手的分数差的最大值,如何从这个定义出发确保两个玩家都采取最优策略?
▷🦆
你们如何确定动态规划的转移方程是s减去min(dp),这里的min(dp)代表了什么意义?
▷🦆
在题解的最后比较`dp[0] > s - dp[0]`来决定获胜者,这种方法是否有可能因为累加过程中的数值溢出而导致结果错误?
▷🦆
为什么在计算每个位置的最优解时,只需要考虑取1, 2, 或3堆石子的情况,而不是更多堆?
▷