剑指 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点可能会有重叠,因为同一个数字可能有多种组合方式,这些不同的组合的概率应该加起来才是构成这个点数真正的概率。
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)