题目名称:新 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
提示:
思路分析
首先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];
}
结果
算法复杂度分析
- 时间复杂度:
- 空间复杂度: