LeetCode——837. 新21点
作者:互联网
新21点
题目描述
爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:
爱丽丝以 0 分开始,并在她的得分少于 K 分时抽取数字。 抽取时,她从 [1, W] 的范围中随机获得一个整数作为分数进行累计,其中 W 是整数。 每次抽取都是独立的,其结果具有相同的概率。
当爱丽丝获得不少于 K 分时,她就停止抽取数字。 爱丽丝的分数不超过 N 的概率是多少?
示例
输入:N = 21, K = 17, W = 10
输出:0.73278
题解
爱丽丝获胜的概率只与下一轮开始的得分有关,因此求解方向是要根据得分计算概率。
令dp[x]
表示从当前得分为x的情况下开始游戏并且获胜的概率,目标是求出dp[0]
的值。
根据规则,当分数达到或是超过K时游戏结束,游戏结束时,如果分数不超过N则获胜,如果分数超过N则失败,因此当 \(K \leq x \leq min(N,K+W-1)\)时有\(dp[x]=1\),当\(x>min(N,K+W-1)\)时有\(dp[x]=0\)。
对于\(min(N,K+W-1)\),根据规则,首先只有在分数不超过N时才获胜;其次,可以达到的最大的分数就是\(K+W-1\),也就是说在最后一次抽取数字之前的分数为K-1,并抽到了W。
当\(0 \leq x \leq K\)时,如何就是\(dp[x]\)的值?注意到每次在范围\([1,W]\)内随机抽取一个整数,其每个整数被抽取到的概率相等,因此可以得到如下的状态转移方程:
\[dp[x]=\frac{dp[x+1]+dp[x+2]+...+dp[x+W]}{W} \]
class Solution {
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 <= N && i < K + W; i++) {
dp[i] = 1.0;
}
for (int i = K - 1; i >= 0; i--) {
for (int j = 1; j <= W; j++) {
dp[i] += dp[i + j] / W;
}
}
return dp[0];
}
}
优化
在上述代码中,计算\(dp[i]\)的时间复杂度为\(O(N+KW)\)需要将其优化
方法一
声明一个变量用来存储\(W\)个\(dp[i]\)的和,每次计算后,去掉变量中最后面的\(dp[i]\)数据并且加上这次计算得出的\(dp[i]\)的数据
代码
class Solution {
public:
double new21Game(int N, int K, int W) {
if (K==0) return 1.0;
vector<double> dp(K + W + 1);
double ans = 0;
for(int i = K; i<=N && i<K+W ; i++){
dp[i] = 1.0;
ans+=dp[i];
}
for(int i = K-1;i>=0;i--){
dp[i]= 1.0/W*(ans);
ans-=dp[i+W];
ans+=dp[i];
}
return dp[0];
}
};
方法二
对\(dp\)的相邻项的计算分差,有如下结果:
\[dp[x]-dp[x+1]=\frac{dp[x+1]-dp[x+W+1]}{W} \]
转换成:
\[dp[x]=dp[x+1]+\frac{dp[x+1]-dp[x+W+1]}{W} \]
其中\(0 \leq x < K-1\)。
那么对于\(x=K-1\)
\[dp[K-1] = \frac{dp[K]+dp[K+1]+...+dp[K+W-1]}{W} \]
其中 当 \(K \leq x \leq min(N,K+W-1)\)时有\(dp[x]=1\),当\(x>min(N,K+W-1)\)时有\(dp[x]=0\)
因此
\[dp[K-1] = \frac{min(N,K+W-1)-K+1}{W} = \frac{min(N-K+1,W)}{W} \]
代码:
class Solution {
public:
double new21Game(int N, int K, int W) {
if (K == 0) {
return 1.0;
}
vector<double> dp(K + W + 1);
for (int i = K; i <= N && i < K + W; i++) {
dp[i] = 1.0;
}
dp[K - 1] = 1.0 * 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];
}
};
标签:frac,837,min,int,double,leq,LeetCode,dp,21 来源: https://www.cnblogs.com/flandre2333/p/13044062.html