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日

相关推荐

  • leetcode1413-逐步求和得到正数的最小值

    原题 给你一个整数数组 nums 。你可以选定任意的 正数 startValue 作为初始值。 你需要从左到右遍历 nums 数组,并将 startValue 依次累加上 nums…

    算法 2020年6月21日
    03040
  • leetcode409-最长回文串

    原题 给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。 在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。 注意:假设字符串的长…

    算法 2020年3月19日
    0570
  • leetcode561-数组拆分I

    原题 给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从1 到 n 的 min(ai, b…

    算法 2019年11月18日
    0100
  • leetcode429-N叉树的层序遍历

    原题 给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 例如,给定一个 3叉树 : 返回其层序遍历: [ [1], [3,2,4], [5,6] ] 说明:…

    2020年1月20日
    0140
  • leetcode1028-从先序遍历还原二叉树

    原题 我们从二叉树的根节点 root 开始进行深度优先搜索。 在遍历中的每个节点处,我们输出 D 条短划线(其中 D 是该节点的深度),然后输出该节点的值。(如果节点的深度为 D,…

    2020年6月18日
    02430
  • leetcode144-二叉树的前序遍历

    原题 给定一个二叉树,返回它的 前序 遍历。 示例: 输入: [1,null,2,3]  1   \    2 &nbs…

    算法 2020年1月10日
    0130
  • leetcode403-青蛙过河

    原题 一只青蛙想要过河。 假定河流被等分为 x 个单元格,并且在每一个单元格内都有可能放有一石子(也有可能没有)。 青蛙可以跳上石头,但是不可以跳入水中。 给定石子的位置列表(用单…

    算法 2020年6月16日
    04640
  • leetcode820-单词的压缩编码

    原题 给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。 例如,如果这个列表是 ["time", "me", "bell"],我们就可以将其表示为 S …

    算法 2020年3月28日
    090
  • leetcode6-Z 字形变换

    原题 https://leetcode.cn/problems/zigzag-conversion/description 解法 遍历每行,按照对称规律都能找到下一个要遍历的下标是…

    算法 2024年3月23日
    0230
  • leetcode234-回文链表

    原题 请判断一个链表是否为回文链表。 示例1: 输入: 1->2 输出: false 示例2: 输入: 1->2->2->1 输出: true 进阶: 你能否用 O(n) 时间复杂…

    2019年12月16日
    0120

发表回复

登录后才能评论