leetcode837-新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

提示:

  1. 0 <= K <= N <= 10000
  2. 1 <= W <= 10000
  3. 如果答案与正确答案的误差不超过 10^-5,则该答案将被视为正确答案通过。
  4. 此问题的判断限制时间已经减少。

解法

思想

可以从dfs的角度入手,这是自顶向下的解法,但比较耗时,

于是可以转换为动态规划。

代码

未经优化的DFS,计算了很多重复单元:

class Solution {
    int K;
    int W;
    int N;
    public double new21Game(int N, int K, int W) {
        this.K = K;
        this.W = W;
        this.N = N;
        return dfs(0,1.0);
    }

    public double dfs(int cur,double p){
        if(cur>=K){
            if(cur<=N){
                return p;
            }
            return 0.0;
        }
        double ans = 0.0;
        for(int i = 1;i<=W;i++){
            ans += dfs(cur+i,p/W);
        }
        return ans;
    }
}

加入记忆化后的DFS,仍然超时:

class Solution {
    int K;
    int W;
    int N;
    Double[][] memory;
    public double new21Game(int N, int K, int W) {
        this.K = K;
        this.W = W;
        this.N = N;
        memory = new Double[K][K];
        return dfs(0,0);
    }

    public double dfs(int cur,int depth){
        if(cur>=K){
            if(cur<=N){
                return Math.pow(1.0/W,depth);
            }
            return 0.0;
        }
        if(memory[cur][depth]!=null) return memory[cur][depth];
        double ans = 0.0;
        for(int i = 1;i<=W;i++){
            ans += dfs(cur+i,depth+1);
        }
        memory[cur][depth] = ans;
        return ans;
    }
}

那么需要进一步优化,通过分析发现,这里的概率其实仅和cur有关,即memory[cur][depth] == Math.pow(1.0/W,depth) * memory[cur][0],因此只需要计算出memory[0][0],memory[1][0],memory[2][0]...就能完成大部分计算。

于是可以使用动态规划来做(用dfs会特别麻烦):

class Solution {
    public double new21Game(int N, int K, int W) {
        if (K == 0) {
            return 1.0;
        }
        double[] dp = new double[K + W];
        for (int i = K; i <= N && i < K + W; 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];
    }
}

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/leetcode837-%e6%96%b021%e7%82%b9/

(0)
彭晨涛彭晨涛管理者
上一篇 2020年6月2日
下一篇 2020年6月3日

相关推荐

  • 剑指offer40-最小的k个数

    原题(来源Leetcode) 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。 示例 1: …

    算法 2020年3月20日
    0390
  • leetcode485-最大连续1的个数

    原题 给定一个二进制数组, 计算其中最大连续1的个数。 示例 1: 输入: [1,1,0,1,1,1] 输出: 3 解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是…

    算法 2019年11月20日
    0130
  • 程序员面试金典01.06-字符串压缩

    原题(来源Leetcode) 字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字…

    算法 2020年3月16日
    0240
  • leetcode155-最小栈

    原题 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。 push(x) – 将元素 x 推入栈中。 pop() – 删除栈顶的元素。 top() …

    算法 2019年12月11日
    0130
  • leetcode297-二叉树的序列化与反序列化

    原题 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。…

    算法 2020年1月15日
    0120
  • leetcode210-课程表II

    原题 现在你总共有 n 门课需要选,记为 0 到 n-1。 在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0…

    算法 2020年5月17日
    0130
  • leetcode5-最长回文子串

    原题 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例1: 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有…

    算法 2020年2月20日
    0110
  • leetcode135-分发糖果

    原题 老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。 你需要按照以下要求,帮助老师给这些孩子分发糖果: 每个孩子至少分配到 1 个…

    算法 2020年2月17日
    060
  • leetcode92-反转链表

    原题 https://leetcode.cn/problems/reverse-linked-list-ii/description 题解 头插法 /** * Definition…

    算法 2024年3月28日
    060
  • leetcode154-寻找旋转排序数组中的最小值II

    原题 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 请找出其中最小的元素。…

    算法 2020年1月7日
    090

发表回复

登录后才能评论