(python)小菜狗算法日记(动态规划系列)_leetcode 面试题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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof

动态规划:把种数存进动态规划的框里。当掷一次骰子时,总的情况有6种1,2,3,4,5,6.每种的概率都是1/6

掷两次骰子时,可以观察出总的点数范围为2--12.同理n次的范围为n-6n。因为最少为每个骰子都1,最多为每个骰子都n。

两次时总的情况为36.因为第一次有6种可能,第二次也是,所以总的种数可能是6的n次方。

那么2--12这些总的点数分别都有几种可能呢。比如2,只能是第一次1,第二次也1这一种可能。3可能是第一次1,第二次2,也可能是第一次2,第一次1,共两种。4可能是22,13,31三种。5可能是14,41,23,32四种以此类推。

抽象出来这些可能的种数怎么得到呢。只考虑最后一次n的情况,用dp[n,s]表示掷n次点数之和为s的种数。n由n-1的情况再掷一次得到,掷第n次有1,2,3,4,5,6这些可能,第n次是1时,前n-1次总和是s-1,第n次是2时,前n-1次总和是s-2,第n次是3时,前n-1次总和是s-3以此类推。因此dp[n,s]=dp[n-1,s-1]+dp[n-1,s-2]+dp[n-1,s-3]+dp[n-1,s-4]+dp[n-1,s-5]+dp[n-1,s-6],这就是状态转移方程。类比于跳台阶那道题,可以跳一阶或两阶。第n阶总的种类就由n-1和n-2的和得到。

初始化掷1次都为1,从1开始把0的位置放0.[0][1][1][1][1][1][1][1]

掷两次的结果由一次的得到。dp[2][2]=dp[1][1]。为了略去一些不符合的。比如2-6,2-5....2-2。用i-j>=0。i是点数总和,j是第n次掷的点数。因为第n次不能大于等于总的点数,从第二次开始,第一次至少有1,所以总的点数-第n次的点数>=1。dp[2][3]=dp[1][1]+dp[1][2],也就是第一次是1的种数第二次固定是2+第一次是2的种数第二次固定是1.

这样求出第n行的动态规划值以后用每个值除以6的n次方就是概率列表。

由于每次至于要第n-1行得到第n行的动态规划数组,为了节省空间,只用一行n列的数组来存储,但需要从后往前更新,因为如果从前往后,前面的数本来是n-1行的种数更新成n行的了,后面的就不对了。同时在更新自身的时候应该先把自身为0 dp[i]=0.因为 dp[i]+=dp[i-j]这句如果自身原本有值会造成干扰。

class Solution:
    def twoSum(self, n: int) -> List[float]:
        #动态规划
        if n==0:
            return []
        dp = [0]*(6*n+1)
        for i in range(1,7):
            dp[i]=1
        for _ in range(n-1):#如n=1不更新,n=2更新一轮以此类推
            for i in range(6*n,0,-1): #6n到1
                dp[i]=0
                for j in range(1,7):#1到6
                    if i-j>=1:
                        dp[i]+=dp[i-j]
        res = []
        all = 6**n
        for i in range(n,6*n+1):#n到6n
            res.append(dp[i]/all)
        return res


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值