新21点
时间:2022-07-22
本文章向大家介绍新21点,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
问题描述:
爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:
爱丽丝以 0 分开始,并在她的得分少于 K 分时抽取数字。 抽取时,她从 [1, W] 的范围中随机获得一个整数作为分数进行累计,其中 W 是整数。 每次抽取都是独立的,其结果具有相同的概率。
当爱丽丝获得不少于 K 分时,她就停止抽取数字。 爱丽丝的分数不超过 N 的概率是多少?
示例 1:
输入:N = 10, K = 1, W = 10
输出:1.00000
说明:爱丽丝得到一张卡,然后停止。
示例 2:
输入:N = 6, K = 1, W = 10
输出:0.60000
说明:爱丽丝得到一张卡,然后停止。
在 W = 10 的 6 种可能下,她的得分不超过 N = 6 分。
示例 3:
输入:N = 21, K = 17, W = 10
输出:0.73278
提示:
0 <= K <= N <= 10000
1 <= W <= 10000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/new-21-game
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
大体思路
当爱丽丝手里的牌大于等于k时就停止抽牌,求解其最终手牌点数小于等于N的概率。由于该问题带有条件概率,因此不能简单地使用dfs列举出所有可能取值,用小于N结果数目除以总数目。
如下以W = 3, N = 3, K = 2为例说明
可以抽出如下几种情况
情况(第一次 第二次) 概率
1 1 1/3*1/3
1 2 1/3*1/3
1 3 1/3*1/3
2 1/3
3 1/3
dfs思路
我们定义函数dfs(sum)为当前值为sum,在题目抽牌条件下,最终结果小于等于N的概率。我们可以得到递推式为:
递归出口:
sum>=k时即不能抽的时候,此时sum大于N返回0,sum小于等于N返回1。
实现代码如下:
public double dfs(int sum, int N, int K, int W){
if(sum >= K){
return sum <= N ? 1.0 : 0.0;
}
double ans = 0.0;
for(int i = 1; i <= W; i++){
ans += dfs(sum + i, N, K, W) / W;
}
return ans;
}
动态规划
与dfs大体思路相同,定义一大小为K + M长的double型数组dp, dp[i]为当前值为i,最终分数不超过N的概率。由于我们可以进行抽牌的最大手牌数为K - 1,则其最终最大手牌数为K + M - 1,因此定义K + M长的数组。
转移方程:
baseline:
class Solution {
public double new21Game(int N, int K, int W) {
double[] dp = new double[K + W];
for(int i = K; i < dp.length; i++){
if(i > N){
break;
}
dp[i] = 1;
}
for(int i = K - 1; i >= 0; i--){
for(int j = 1; j <= W; j++){
if(i + j > N){
break;
}
dp[i] += dp[i + j] / W;
}
}
return dp[0];
}
}
时间复杂度为0(K * W)
优化后的dp
从上一节可知:
因此可以由该式推出如下式子:
由于i的最大取值为K - 1,其转移方程中最大要用到dp[K + W]的值,而我们的dp下标最大取值为K + W - 1,因此baseline中应该先利用上一节的递推公式计算出dp[K - 1]的值,然后从K-2往前递推。
实现代码如下:
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 < dp.length; i++){
if(i > N){
break;
}
dp[i] = 1;
}
for(int j = 1; j <= W; j++){
dp[K - 1] += dp[K - 1 + j] / W;
}
for(int i = K - 2; i >= 0; i--){
dp[i] = (dp[i + 1] + W * dp[i + 1] - dp[i + 1 + W]) / W;
}
return dp[0];
}
}
时间复杂度为O(W + K)
- 利用message queue实现aspx与winform通信, 并附完整示例
- 10招步骤保护IIS服务器安全
- Haproxy+Keepalived高可用环境部署梳理(主主和主从模式)
- Android-Universal-Image-Loader 图片异步加载类库的使用
- 工作组模式下专用队列(Private Queue)如何引用远程队列路径
- haproxy反向代理环境部署(http和https代理)
- 网站速度优化模块HttpCompressionModule
- mysql启动后随即关闭问题解决(ibdata1文件损坏导致)
- webvirtmgr-重命名kvm虚拟机的名称
- Lucene 2.0最基本的入门代码
- 网站每日PV/IP统计/总带宽/URL统计脚本分享(依据网站访问日志)
- 查看服务器系统资源(cpu,内容)利用率前几位的进程的方法
- 腾讯云平台部总经理陈磊:大数据背后的技术支撑
- DataSet与Xml相互转化
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Alertmanager 安装与使用
- typedef用法
- LaTex中插入大括号的多行公式
- Latex公式编辑和子公式编辑
- nginx rewrite 跨域
- Oracle删除索引规范
- mysql中走与不走索引的情况汇集(待全量实验)
- C#标准事件流
- 【STM32F407开发板用户手册】第25章 STM32F407的TIM定时器基础知识和HAL库API
- 【STM32F429开发板用户手册】第25章 STM32F429的TIM定时器基础知识和HAL库API
- AkShare-债券数据-全球债券行情
- AkShare-指数数据-全球指数
- AkShare-股票数据-机构推荐
- AkShare-债券数据-可转债
- AkShare-股票数据-基金持股