石子游戏
难度:
标签:
题目描述
代码结果
运行时间: 1004 ms, 内存: 173.8 MB
// Java Stream solution for the problem
// 思路: 我们可以使用动态规划的思想,通过Java Stream的特性简化代码。每次迭代计算出每个区间的最大得分,然后使用流处理的方式更新。
import java.util.stream.IntStream;
public class StoneGame {
public boolean stoneGame(int[] piles) {
int n = piles.length;
int[][] dp = IntStream.range(0, n).mapToObj(i -> new int[n]).toArray(int[][]::new);
IntStream.range(0, n).forEach(i -> dp[i][i] = piles[i]); // 初始化
IntStream.range(2, n + 1).forEach(l -> // l是区间长度
IntStream.range(0, n - l + 1).forEach(i -> {
int j = i + l - 1;
dp[i][j] = Math.max(piles[i] - dp[i + 1][j], piles[j] - dp[i][j - 1]);
})
);
return dp[0][n - 1] > 0; // 判断先手是否能赢
}
}
解释
方法:
这个题解使用了动态规划的思路。定义了一个二维的备忘录memo,用于记录区间 [i, j] 内先手和后手最多能拿到的石子数。
在 dp 函数中,对区间 [i, j] 进行划分,如果区间长度为 1,直接返回该堆石子的数量。否则,分别计算先手拿左边或右边的石子堆时,对手能拿到的最大数量。最后返回两种情况下,先手能拿到石子数更多的那个。
在主函数中,调用 dp(0, n-1),返回先手和后手拿到的石子数,比较大小即可判断先手是否获胜。
时间复杂度:
O(n^2)
空间复杂度:
O(n^2)
代码细节讲解
🦆
在动态规划问题中,为什么选择使用一个二维备忘录memo来存储每个子问题的结果,而不是其他数据结构如数组?
▷🦆
细节问题:在dp函数中,当区间长度为1时,为什么返回的元组中第二个元素是0?这是否意味着只有一个玩家可以拿石子?
▷🦆
在决定先手拿左边还是右边的石子时,如何确定哪种选择能够确保先手最终拿到的石子数最多?
▷🦆
题解中提到,比较dp(0, n-1)返回的先手和后手的石子数以判断先手是否获胜,是否有更直接的方法来预测游戏的结果?
▷