其他分享
首页 > 其他分享> > LeetCode——837. 新21点

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