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日

相关推荐

  • leetcode96-不同的二叉搜索树

    原题 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: &…

    算法 2020年1月22日
    0120
  • leetcode454-四数相加II

    原题 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。 为…

    算法 2019年12月27日
    080
  • leetcode701-二叉搜索树中的插入操作

    原题 给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 保证原始二叉搜索树中不存在新值。 注意,可能存在多种有效的插入方式,只…

    算法 2020年1月16日
    0100
  • leetcode86-分隔链表

    原题 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。 你应当保留两个分区中每个节点的初始相对位置。 示例: 输入: head…

    算法 2020年4月27日
    0150
  • leetcode210-课程表II

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

    算法 2020年5月17日
    0130
  • leetcode561-数组拆分I

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

    算法 2019年11月18日
    090
  • leetcode46-全排列

    原题 给定一个没有重复数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3] 输出: [   [1,2,3],   [1,3,…

    算法 2020年3月3日
    0180
  • leetcode429-N叉树的层序遍历

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

    2020年1月20日
    0140
  • 剑指offer04-二维数组中的查找

    原题(来源Leetcode) 在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个…

    算法 2020年4月4日
    0140
  • leetcode119-杨辉三角II

    原题 给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。在杨辉三角中,每个数是它左上方和右上方的数的和。 示例: 输入: 3 输出: [1,3,3,1] 进阶: …

    2019年11月22日
    0280

发表回复

登录后才能评论