LC837-新 21 点

171 阅读2分钟

题目名称:新 21 点

爱丽丝参与一个大致基于纸牌游戏  “21点”  规则的游戏,描述如下:

爱丽丝以 0 分开始,并在她的得分少于 k 分时抽取数字。 抽取时,她从 [1, maxPts] 的范围中随机获得一个整数作为分数进行累计,其中 maxPts 是一个整数。 每次抽取都是独立的,其结果具有相同的概率。

当爱丽丝获得 k 分 或更多分 时,她就停止抽取数字。

爱丽丝的分数不超过 n 的概率是多少?

与实际答案误差不超过 10-5 的答案将被视为正确答案。

  示例 1:

输入: n = 10, k = 1, maxPts = 10
输出: 1.00000
解释: 爱丽丝得到一张牌,然后停止。

示例 2:

输入: n = 6, k = 1, maxPts = 10
输出: 0.60000
解释: 爱丽丝得到一张牌,然后停止。 在 10 种可能性中的 6 种情况下,她的得分不超过 6 分。

示例 3:

输入: n = 21, k = 17, maxPts = 10
输出: 0.73278

提示:

  • 0<=k<=n<=1040 <= k <= n <= 10^4
  • 1<=maxPts<=1041 <= maxPts <= 10^4

思路分析

首先dp[x] 代表 从分数为x的情况下开始游戏,然后获胜的概率,答案是dp[0]

首先明确 K 代表 得分小于K才能抽牌 N代表摸牌后,牌值累加的最后结果要不大于N才能赢 W代表可以从[1,W]之间抽牌

那么若从K - 1(最大起始牌,再超过这个牌就不能抽了) 开始抽牌 那么获胜的概率就等于 (dp(x + 1) + ..... + dp(x + w)) / W

dp[x] 和 dp[x + 1] 之间的关系为 dp[x] = dp[x + 1] - (dp[x + 1 + W] - dp[x + 1]) / W (这也就是题目的状态转移方程)

还有一些注意点,当N > k + W 时 在下列代码中给dp[k--- N] 进行初始化的时候 会出现数组越界的情况

比如示例3的数据 把N从21改成28,但是数组才开了28,下标是到不了dp[28]的,所以就出现了越界,就要在循环体的限制条件中多加一层判断即可

因为dp[x] = dp[x + 1] - (dp[x + 1 + W] - dp[x + 1]) / W 对 x = k - 1的时候不适用 因为dp[k]是初始化为1的

Code实现

public double new21Game(int N, int K, int W) {
    if (K == 0) return 1.0;
    double[] dp = new double[K + W + 1];
    for (int i = K; i < K + W && i <= N; i++) {
        dp[i] = 1.0;
    }
    dp[K - 1] = 1.0 * Math.min(N - K + 1, W) / W;
    for (int i = K - 2; i >= 0; i--) {
        dp[i] = dp[i + 1] - (dp[i + W + 1] - dp[i + 1]) / W;
    }
    return dp[0];
}

结果

Snipaste_2023-04-20_20-01-43.png

算法复杂度分析

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)