爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:
爱丽丝以 0
分开始,并在她的得分少于 k
分时抽取数字。 抽取时,她从 [1, maxPts]
的范围中随机获得一个整数作为分数进行累计,其中 maxPts
是一个整数。 每次抽取都是独立的,其结果具有相同的概率。
当爱丽丝获得 k
分 或更多分 时,她就停止抽取数字。
爱丽丝的分数不超过 n
的概率是多少?
与实际答案误差不超过 10-5
的答案将被视为正确答案。
网友代码
class Solution {
public:
double new21Game(int N, int K, int M) {
// dp[i]:当前得分为 i 时,最终分数不超过 N 的概率
double dp[K + M];
// s:滑动窗口内 dp 值的和,用于 O(1) 计算区间平均
double s = 0;
// 初始化 K ~ K+M-1 区间的边界值
for (int i = K; i < K + M; ++i) {
// 若 i 不超过 N 则后续一定满足条件,概率为 1;否则为 0
dp[i] = (i <= N) ? 1.0 : 0.0;
s += dp[i];
}
// 逆序计算 0 ~ K-1 的概率
for (int i = K - 1; i >= 0; --i) {
// 从 1~M 中均匀抽取一张牌,求期望概率
dp[i] = s / M;
// 滑动窗口:去掉最右端 dp[i+M],加入新的 dp[i]
s = s - dp[i + M] + dp[i];
}
// 返回从 0 分开始游戏,最终得分不超过 N 的概率
return dp[0];
}
};
转换思路
求爱丽丝的胜率。她可以从牌面为 [1,M] 的牌中选择任意一张,这张牌是可以无限重复的,也就是说无论她取多少次,每次取到 2(假如 2 在 [1,M] 范围内)的概率都是 1/M;如果她手上牌的总额小于 K,她就会抽牌,大于等于 K 时,就停止抽牌;停止抽牌后,她的牌面小于等于 N 时,她就获胜了,求她获胜的概率。
假设 dp[x] 为她手上牌面为x时,能获胜的概率,那么这个概率应该是: dp[x]=1/M * (dp[x+1]+dp[x+2]+dp[x+3]...+dp[x+M]) 因为抽取的牌面机会都是均等的,她能抽取的面值在 [1,M] 之间,所以将概率之和平均一下就是 dp[x] 的概率。
x 最多能到 K-1,因为当大于等于 K 时,爱丽丝会停止抽牌,所以当游戏结束时,即爱丽丝停止抽牌时,她可能达到的最大牌面是 K+M-1,而一开始她的牌面是 0,所以我们用一个长度为 K+M 的 dp 数组来保存她在所有面值下的胜率。 最后 dp[0],也就是最开始爱丽丝还没有抽牌,她的牌面为 0 时的胜率,这个就是我们的答案。
抖音讲解视频
5.89 01/24 JVY:/ I@V.lc 837.新 21 点 # 每日一题# 算法 # 数据结构 # Leetcode https://v.douyin.com/hmzADkH0ByE/ 复制此链接,打开Dou音搜索,直接观看视频!
哔站讲解视频
【837.新 21 点】 https://www.bilibili.com/video/BV1SzYyzgEwA/?share_source=copy_web&vd_source=9ce5dcc0dc00db11597011753f36587b