夯实算法-40.新 21 点

183 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

题目:LeetCode

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

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

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

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

与实际答案误差不超过 10510^-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[i]表示转移到i的概率和,则我们可以轻易求得转移方程dp[i]=(dp[i-W]+dp[i-W+1]+....+dp[i-1])/W,乍一看感觉需要O(N*W)的复杂度,但是位置i只和前W个连续的状态有关,因此我们采用类似尺取求前缀和思想便能时刻更新前W个连续状态的值

  • 当K分数小于N时 概率都为1
  • 分数不超过N时才能概率1.0;可以达到的最大分数为 K+W-1
  • 得分为i开始的概率递推式等于得分为i+1开始的概率-不超过N的概率
  • i=0是从0开始的概率,即题目要求

代码实现

public double new21Game(int N, int K, int W) {
    if(K == 0) return 1.0;

    double[] dp = new double[K + W];
    for(int i = K; i <= N && i < K + W; i++){
        dp[i] = 1.0;
    }
    dp[K - 1] = 1.0 * Math.min(N - K + 1, W) / W;  // 注意 * 1.0 作类型转换
    for(int i = K - 2; i >= 0; i--){
        dp[i] = dp[i + 1] - (dp[i + 1 + W] - dp[i + 1]) / W;
    }
    return dp[0];
}

运行结果

微信截图_20221021235014.png

复杂度分析

  • 时间复杂度:O(n2)O(n^2)
  • 空间复杂度:O(n)O(n)

掘金(JUEJIN)  一起分享知识, Keep Learning!