这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战
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个骰子,如果采用暴力法,那么时间复杂度将会达到O(),显然不切实际。
动态规划
由于后面的概率或者点数和与前面骰子的概率和点数和有关系,我们可以使用动态规划的方式解决这道题。
步骤如下:
- 设置dp为每轮掷骰子的点数和的概率,初始为点数和为1-6的概率均为。
- 根据掷骰子的次数,来进行循环
- 设置tmp为该轮掷骰子的点数和的概率,初始为全0。若掷5颗骰子,5个全1的情况下,能得到最小的点数和为5,同理,不难得出最小点数和为。
- 根据上一次的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()
- 空间复杂度:O()
坚持每日一练!前端小萌新一枚,希望能点个赞哇~