🧮 Algorithm Notebook
1、算法准备
1.1 牛客网编程OJ的典型输入输出
2、算法框架
2.1 动态规划
2.1.1 斐波那契数列
2.1.2 背包问题
2.1.3 贪心算法
2.1.4 序列和数组类问题
2.1.5 编辑距离
2.1.6 高楼扔鸡蛋
2.1.7 股票问题系列通解
2.1.8 最长有效括号
2.1.9 剪绳子
2.1.10 正则表达式匹配
2.2 二分查找
2.2.1 二分查找框架
2.2.2 搜索旋转排序数组
2.3 链表
2.3.1 反转链表
2.3.2 相交链表
2.3.3 合并链表
2.3.4 链表中倒数第k个节点
2.3.5 复制带随机指针的链表
2.4 排序算法
2.4.1 常见排序算法
2.5 二叉树
2.5.1 二叉树遍历
2.5.2 岛屿问题
2.5.3 二叉树路径问题
2.5.4 构造二叉树
2.6 回溯算法
2.6.1 回溯算法解题框架
2.6.2 N皇后
2.7 数组
2.7.1 删除有序数组中的重复项
2.7.2 滑动窗口最大值
2.7.3 调整数组顺序使奇数位于偶数前面
2.7.4 螺旋矩阵
2.7.5 多数元素
2.7.6 最大数
2.7.7 和为s的两个数字
2.7.8 构建乘积数组
2.7.9 两数之和
2.8 字符串
2.8.1 最小覆盖子串
2.8.2 比较版本号
2.8.3 验证IP地址
2.8.4 基本计算器 II
2.8.5 字符串解码
2.8.6 移掉 K 位数字
2.8.7 无重复字符的最长子串
2.8.8 第一个只出现一次的字符
2.8.9 翻转字符串里的单词
2.8.10 字符串转换整数 (atoi)
2.8.11 字符串四则运算
2.9 栈
2.9.1 最小栈
2.9.2 弹出序列
2.10 数学
2.10.1 用 Rand7() 实现 Rand10()
2.10.2 只出现一次的数字
2.10.3 整数反转
2.10.4 求1+2+…+n
2.10.5 二进制中1的个数
2.10.6 幂运算
2.10.7 1~n 整数中 1 出现的次数
2.10.8 数字序列中某一位的数字
2.10.9 丑数
2.10.10 n个骰子的点数
2.10.11 圆圈中最后剩下的数字
2.10.12 不用加减乘除做加法
2.10.13 x 的平方根
2.11 设计
2.11.1 LRU 缓存机制
-
+
tourist
register
Sign in
n个骰子的点数
## 1 题目 把 n 个骰子扔在地上,所有骰子朝上一面的点数之和为 s。输入 n,打印出 s 的所有可能的值出现的概率。 你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。 **示例 1:** ```txt 输入: 1 输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667] ``` **示例 2:** ```txt 输入: 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 ## 2 解题思路 ### 2.1 动态规划 #### 2.1.1 问题分析 1. **设输入 $n$ 个骰子的解**(即概率列表)**为 $f(n)$**,**其中点数和 $x$ 的概率为 $f(n, x)$**。 2. **假设已知 $n - 1$ 个骰子的解 $f(n - 1)$**,**此时添加一枚骰子**,**求 $n$ 个骰子的点数和为 $x$ 的概率 $f(n, x)$**。 3. **当添加骰子的点数为 1 时**,**前 $n - 1$ 个骰子的点数和应为 $x - 1$**,**方可组成点数和 $x$**,**同理**,**当此骰子为 2 时**,**前 $n - 1$ 个骰子应为 $n - 2$**,**以此类推**,**直至此骰子点数为 6**,**将这 6 种情况的概率相加**,**即可得到概率 $f(n, x)$**,**递推公式如下所示**: $$ f(n, x) = \sum^6_{x = 1}f(n - 1, x - i) \times \frac16 $$ 4. **根据以上分析**,**得知通过子问题的解 $f(n - 1)$ 可递推计算出 $f(n)$**,**而输入一个骰子的解 $f(1)$ 已知**,**因此可通过解 $f(1)$ 依次递推出任意解 $f(n)$**,如下图所示,为 $n = 2, x = 7$ 的递推计算示意图: ![Picture2.png](/media/202202/2022-02-12_1057170.3733175875882666.png) 5. **观察发现**,**以上递推公式虽然可行**,**但 $f(n - 1, x - i)$ 中的 $x - i$ 会有越界问题**,例如,若希望递推计算 $f(2, 2)$,由于一个骰子的点数和范围为 $[1, 6]$,因此只应求和 $f(1, 1)$,即 $f(1, 0), f(1, -1),..., f(1, -4) $ 皆无意义。 6. **上面的递推公式是逆向的**,**即为了计算 $f(n, x)$**,**将所有与之相关的情况求和**,**而倘若改换为正向的递推公式**,**便可解决问题**,**具体来看**,**由于新增骰子的点数只可能为 1 至 6**,**因此概率 $f(n - 1, x)$ 仅与 $f(n, x + 1), f(n, x + 2),..., f(n, x + 6)$ 相关**,**因而**,**遍历 $f(n + 1)$ 中各点数和的概率**,**并将其相加至 $f(n)$ 中所有相关项**,**即可完成 $f(n - 1)$ 至 $f(n)$ 的递推**。 ![Picture3.png](/media/202202/2022-02-12_1106230.40331717078644014.png) 7. 具体实例如下: ![](/media/202202/2022-02-12_1106440.512448934251122.png) ![](/media/202202/2022-02-12_1106520.32350363339285904.png) ![](/media/202202/2022-02-12_1107010.2953053321677126.png) ![](/media/202202/2022-02-12_1107090.5823211622074699.png) ![](/media/202202/2022-02-12_1107170.24416546346844548.png) ![](/media/202202/2022-02-12_1107240.33870643211913043.png) ![](/media/202202/2022-02-12_1107320.398163178063511.png) ![](/media/202202/2022-02-12_1107400.6363814827314325.png) ![](/media/202202/2022-02-12_1107500.07696989614018224.png) #### 2.1.2 参考代码 ```java /** *剑指 Offer 60. n 个骰子的点数 * @param n 骰子的个数 * @return 所有骰子朝上一面的点数之和的所有可能的值出现的概率 */ public double[] dicesProbability(int n) { double[] dp = new double[6]; Arrays.fill(dp, 1.0 / 6.0); for (int i = 2; i <= n; i++) { double[] tmp = new double[5 * i + 1]; for (int j = 0; j < dp.length; j++) { for (int k = 0; k < 6; k++) { tmp[j + k] += dp[j] / 6.0; } } dp = tmp; } return dp; } ``` ## 参考文献 1. [剑指 Offer 60. n 个骰子的点数](https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof)。 2. [ 剑指 Offer 60. n 个骰子的点数(动态规划,清晰图解)](https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/solution/jian-zhi-offer-60-n-ge-tou-zi-de-dian-sh-z36d)。
ricear
Feb. 12, 2022, 11:51 a.m.
©
BY-NC-ND(4.0)
转发文档
Collection documents
Last
Next
手机扫码
Copy link
手机扫一扫转发分享
Copy link
Markdown文件
share
link
type
password
Update password