JS算法之n个骰子的点数

657 阅读2分钟

这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战

n个骰子的点数

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

难度:中等

题目:leetcode-cn.com/problems/ng…

把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个骰子,如果采用暴力法,那么时间复杂度将会达到O(6N6^N),显然不切实际。

动态规划

由于后面的概率或者点数和与前面骰子的概率和点数和有关系,我们可以使用动态规划的方式解决这道题。

步骤如下:

  • 设置dp为每轮掷骰子的点数和的概率,初始为点数和为1-6的概率均为1/61/6
  • 根据掷骰子的次数,来进行循环
    • 设置tmp为该轮掷骰子的点数和的概率,初始为全0。若掷5颗骰子,5个全1的情况下,能得到最小的点数和为5,同理,不难得出最小点数和为6nn+1=5n+16*n - n + 1 = 5n+1
    • 根据上一次的dp结果,与每轮掷骰子的tmp[i]一起交替前进,因为新增骰子的点数只可能是1至6,因此每一次tmp前进时都要加上「上一次的结果/6」。
    • 算完tmp后将tmp赋值给dp,以便下一次可以使用。
  • 遍历结束,返回dp。
/**
 * @param {number} n
 * @return {number[]}
 */
var dicesProbability = function (n) {
  let dp = new Array(6).fill(1/6);
  for (let i = 2; i <= n; i++) {
    let tmp = new Array(5 * i + 1).fill(0);
    for (let j = 0; j < dp.length; j++) {
      for (let k = 0; k < 6; k++) {
        tmp[j + k] += dp[j] / 6;
      }
    }
    dp = tmp;
  }
  return dp;
};
  • 时间复杂度:O(N2N^2)
  • 空间复杂度:O(NN)

坚持每日一练!前端小萌新一枚,希望能点个哇~