题目描述
把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
Leetcode链接:剑指offer面试题60:n个骰子的点数
算法分析
动态规划,每轮递推加入一个骰子计算概率。
函数参数为骰子点数总和,下标表示骰子个数。按如下公式计算即可:
f
n
(
k
)
=
f
n
−
1
(
k
−
1
)
∗
f
1
(
1
)
+
f
n
−
1
(
k
−
2
)
∗
f
1
(
2
)
+
⋅
⋅
⋅
+
f
n
−
1
(
2
)
∗
f
1
(
k
−
2
)
+
f
n
−
1
(
1
)
∗
f
1
(
k
−
1
)
f_n(k) = f_{n-1}(k-1) * f_1(1) + f_{n-1}(k-2) * f_1(2) + ··· + f_{n-1}(2) * f_1(k-2) + f_{n-1}(1) * f_1(k-1)
fn(k)=fn−1(k−1)∗f1(1)+fn−1(k−2)∗f1(2)+⋅⋅⋅+fn−1(2)∗f1(k−2)+fn−1(1)∗f1(k−1)
复杂度分析
问题规模为骰子的个数n
- 时间复杂度:O( n 2 n^2 n2),所有递归中数组dp的长度构成等差数列,用等差数列求和计算循环次数,最终结果为 n 2 n^2 n2数量级。
- 空间复杂度:O( n n n),res最大长度为5n,因此辅助空间最大为O( n n n)。
TypeScript代码如下
function dicesProbability(n: number): number[] {
let base = [1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6];
let dp = [1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6];
let dpFunc = (n: number, dp: number[]): number[] => {
if (n === 0) return dp;
let res = [...Array<number>(base.length + dp.length - 1)].map(() => 0);
for (let i = 0; i < base.length; ++i) {
for (let j = 0; j < dp.length; ++j) {
res[i + j] += base[i] * dp[j];
}
}
return dpFunc(n - 1, res);
};
dp = dpFunc(n - 1, dp);
// 取五位小数
dp = dp.map<number>((item: number): number => {
return Number(item.toFixed(5));
});
return dp;
}