leetcode 剑指 Offer 60. n个骰子的点数

剑指 Offer 60. n个骰子的点数

把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。

你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。

示例 1:

输入: 1
输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]

示例 2:

输入: 2
输出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]

限制:

1 <= n <= 11

思路一:动态规划

动态规划,如果已知n-1个骰子的每个点数对应的概率,那再求n个骰子的点数对应的概率,就是在n-1个骰子的每个点数上面增加1-6点,这样就可以组成n个骰子的所有点数,而在原来的点数上增加一个点数概率其实就是多乘了一个1/6, 因为n-1的点数加上1-6点可能会有重叠,因为同一个数字可能有多种组合方式,这些不同的组合的概率应该加起来才是构成这个点数真正的概率。

具体分析可以参考:https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/solution/java-dong-tai-gui-hua-by-zhi-xiong/

 1 class Solution {
 2     public double[] twoSum(int n) {
 3         double[] pre = {1/6d, 1/6d, 1/6d, 1/6d, 1/6d, 1/6d};
 4         
 5         // 每次增加一个骰子
 6         for(int i = 2; i <= n; i++){
 7             double[] tmp = new double[5 * i + 1];
 8             // 对每个骰子执行:1. 在上一个骰子个数下加上一个骰子,把每个点数都加上0-5, 
 9             for(int j = 0; j < pre.length; j++){
10                 for(int k = 0; k < 6; k++){
11                     // 因为同一个数字可能有多种组合方式,这些不同的组合的概率应该加起来才是构成这个点数真正的概率
12                     tmp[j+k] += pre[j] / 6d;   
13                 }
14             }
15             pre = tmp;
16         }
17 
18         return pre;
19     }
20 }
leetcode 执行用时:0 ms > 100.00%, 内存消耗:39.3 MB > 5.04%

复杂度分析:

时间复杂度:6*(n-1)*(5*1+1 + .. + 5*i+1 + ... + 5*(n-1)+1) = 3(n-1)2(5n+2) = 15n3-24n2+3n+6, 根据公式可以看出来,算法时间复杂度是O(n3)

空间复杂度:需要不断地创建空间,然后又释放掉,同时刻存在的两个最大的内存数组大小分别为(5(n-1)+1)和5n+1, 所以假设每次没有引用指向数组后,数组内存会被自动回收的话,那空间复杂度就是O(n)

posted @ 2020-10-04 16:56  Lucky小黄人^_^  阅读(220)  评论(0编辑  收藏  举报