New 21 Game
MediumUpdated: Aug 2, 2025
Practice on:
Problem
Alice plays the following game, loosely based on the card game "21".
Alice starts with 0 points and draws numbers while she has less than k points. During each draw, she gains an integer number of points randomly from the range [1, maxPts], where maxPts is an integer. Each draw is independent and the outcomes have equal probabilities.
Alice stops drawing numbers when she gets k or more points.
Return the probability that Alice has n or fewer points.
Answers within 10-5 of the actual answer are considered accepted.
Examples
Example 1
Input: n = 10, k = 1, maxPts = 10
Output: 1.00000
Explanation: Alice gets a single card, then stops.
Example 2
Input: n = 6, k = 1, maxPts = 10
Output: 0.60000
Explanation: Alice gets a single card, then stops.
In 6 out of 10 possibilities, she is at or below 6 points.
Example 3
Input: n = 21, k = 17, maxPts = 10
Output: 0.73278
Constraints
0 <= k <= n <= 10^41 <= maxPts <= 10^4
Solution
Method 1 – Dynamic Programming with Sliding Window
Intuition
We use DP where dp[x] is the probability of getting exactly x points. For each state, the probability is the average of the previous maxPts states. To optimize, we use a sliding window sum.
Approach
- If
k == 0orn >= k + maxPts - 1, Alice always wins, return 1. - Initialize
dp[0] = 1and a window sum variable. - For each
ifrom 1 to n:dp[i] = window / maxPts.- If
i < k, adddp[i]to window. - If
i - maxPts >= 0, subtractdp[i - maxPts]from window.
- The answer is the sum of
dp[k]todp[n].
Code
C++
class Solution {
public:
double new21Game(int n, int k, int maxPts) {
if (k == 0 || n >= k + maxPts - 1) return 1.0;
vector<double> dp(n+1);
dp[0] = 1.0;
double window = 1.0, ans = 0.0;
for (int i = 1; i <= n; ++i) {
dp[i] = window / maxPts;
if (i < k) window += dp[i];
else ans += dp[i];
if (i - maxPts >= 0) window -= dp[i - maxPts];
}
return ans;
}
};
Go
func new21Game(n, k, maxPts int) float64 {
if k == 0 || n >= k+maxPts-1 {
return 1.0
}
dp := make([]float64, n+1)
dp[0] = 1.0
window, ans := 1.0, 0.0
for i := 1; i <= n; i++ {
dp[i] = window / float64(maxPts)
if i < k {
window += dp[i]
} else {
ans += dp[i]
}
if i-maxPts >= 0 {
window -= dp[i-maxPts]
}
}
return ans
}
Java
class Solution {
public double new21Game(int n, int k, int maxPts) {
if (k == 0 || n >= k + maxPts - 1) return 1.0;
double[] dp = new double[n+1];
dp[0] = 1.0;
double window = 1.0, ans = 0.0;
for (int i = 1; i <= n; ++i) {
dp[i] = window / maxPts;
if (i < k) window += dp[i];
else ans += dp[i];
if (i - maxPts >= 0) window -= dp[i - maxPts];
}
return ans;
}
}
Kotlin
class Solution {
fun new21Game(n: Int, k: Int, maxPts: Int): Double {
if (k == 0 || n >= k + maxPts - 1) return 1.0
val dp = DoubleArray(n+1)
dp[0] = 1.0
var window = 1.0
var ans = 0.0
for (i in 1..n) {
dp[i] = window / maxPts
if (i < k) window += dp[i]
else ans += dp[i]
if (i - maxPts >= 0) window -= dp[i - maxPts]
}
return ans
}
}
Python
class Solution:
def new21Game(self, n: int, k: int, maxPts: int) -> float:
if k == 0 or n >= k + maxPts - 1:
return 1.0
dp = [0.0] * (n+1)
dp[0] = 1.0
window = 1.0
ans = 0.0
for i in range(1, n+1):
dp[i] = window / maxPts
if i < k:
window += dp[i]
else:
ans += dp[i]
if i - maxPts >= 0:
window -= dp[i - maxPts]
return ans
Rust
impl Solution {
pub fn new21_game(n: i32, k: i32, max_pts: i32) -> f64 {
if k == 0 || n >= k + max_pts - 1 {
return 1.0;
}
let n = n as usize;
let k = k as usize;
let max_pts = max_pts as usize;
let mut dp = vec![0.0; n+1];
dp[0] = 1.0;
let mut window = 1.0;
let mut ans = 0.0;
for i in 1..=n {
dp[i] = window / max_pts as f64;
if i < k {
window += dp[i];
} else {
ans += dp[i];
}
if i >= max_pts {
window -= dp[i - max_pts];
}
}
ans
}
}
TypeScript
class Solution {
new21Game(n: number, k: number, maxPts: number): number {
if (k === 0 || n >= k + maxPts - 1) return 1.0;
const dp = Array(n+1).fill(0);
dp[0] = 1.0;
let window = 1.0, ans = 0.0;
for (let i = 1; i <= n; ++i) {
dp[i] = window / maxPts;
if (i < k) window += dp[i];
else ans += dp[i];
if (i - maxPts >= 0) window -= dp[i - maxPts];
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n)— We fill the DP array once. - 🧺 Space complexity:
O(n)— For the DP array.