《算法零基础100讲》(第30讲) 概率与统计

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法零基础100讲》(第30讲) 概率与统计相关的知识,希望对你有一定的参考价值。

零、写在前面

  这是《算法零基础100讲》 专栏打卡学习的第三十天了。
  每天打卡的题,做不出来没关系,因为困难的题涉及知识点较多,后面还是会开放出来的,就像昨天的 最大公约数 那道题今天还是会有,所以不要着急,内容能看懂,能自己分析,能做出简单题,就可以打卡。
  在刷题的过程中,总结自己遇到的坑点,写出 「 解题报告 」 供他人学习,也是一种自我学习的方式。这就是经典的帮助他人的同时,成就自己。目前, 「 万人千题 」 社区 每天都会有五六篇高质量的 「 解题报告 」 被我 「 加精 」。如果觉得自己有能力的,也可以来发布你的 「 解题报告 」。千万级流量,你我共同拥有。

一、概念定义

  概率这个事情,如果要扯远,那就可以写一本书了。而竞赛或者力扣上的概率题,一般都是和动态规划相结合的,

二、题目描述

  把 n n n 个骰子扔在地上,所有骰子朝上一面的点数之和为 s s s。输入 n n n,打印出 s s s 的所有可能的值出现的概率。你需要用一个浮点数数组返回答案,其中第 i i i 个元素代表这 n n n 个骰子所能掷出的点数集合中第 i i i 小的那个的概率。

三、算法详解

  对于任意一个骰子来讲,丢出任意点数的概率都是 1 6 \\frac 1 6 61,对于 n n n 个骰子来讲,丢出的数值的取值为 [ n , 6 n ] [n, 6n] [n,6n]。试想一下,丢出 n n n 的情况,就是 n n n 个骰子都是 1 的情况,方案数为一种;丢出 6 n 6n 6n 的情况,就是 n n n 个骰子都为 6 的情况,方案数也为一种。
  于是,我们可以这么来看, i i i 个骰子丢出 j j j 的方案数如果为 f [ i ] [ j ] f[i][j] f[i][j],那么丢出 j j j 的概率,就是 f [ i ] [ j ] ∑ k = n 6 n f [ i ] [ k ] \\frac f[i][j]\\sum_k=n^6n f[i][k] k=n6nf[i][k]f[i][j]
  那么,我们来看下怎么求 f [ i ] [ j ] f[i][j] f[i][j],首先 f [ 0 ] [ 0 ] = 1 f[0][0]=1 f[0][0]=1,而对于 i i i 个骰子的情况,它有六种选择方式,分别为 k = 1 − 6 k=1-6 k=16,于是剩下 i − 1 i-1 i1 个骰子的总和就变成了 j − k j-k jk,于是,问题就转变成了求 f [ i − 1 ] [ j − k ] f[i-1][j-k] f[i1][jk]的问题,这样思路就有了,我们可以得到递推式: f [ i ] [ j ] = ∑ k = 1 6 f [ i − 1 ] [ j − k ] f[i][j] = \\sum_k=1^6f[i-1][j-k] f[i][j]=k=16f[i1][jk]
  三层循环递推求解。

四、源码剖析

int dp[12][70];

double* dicesProbability(int n, int* returnSize)
    int i, j, k;
    double f;
    double *ret = (double *)malloc( sizeof(double) * (n * 6 + 1) );
    memset(dp, 0, sizeof(dp));                     // (1)
    dp[0][0] = 1;
    for(i = 1; i <= n; ++i) 
        for(j = 1; j <= 6*n; ++j) 
            dp[i][j] = 0;
            for(k = 1; k <= 6; ++k) 
                if(j >= k)
                    dp[i][j] += dp[i-1][j-k];      // (2)
            
        
    
    f = 1;
    for(i = 0; i < n; ++i) 
        f /= 6;                                    // (3)
    
    *returnSize = 0;
    for(i = 0; i <= 6*n; ++i) 
        if(dp[n][i]) 
            ret[ (*returnSize)++ ] = dp[n][i] * f; // (4)
        
    
    return ret;

  • ( 1 ) (1) (1) d p [ i ] [ j ] dp[i][j] dp[i][j] 代表 i i i 个骰子,组合出点数为 j j j 的方案数;
  • ( 2 ) (2) (2) 枚举第 i i i 个骰子的情况,从而根据子问题求解;
  • ( 3 ) (3) (3) 计算概率对应的分母,也就是和的所有的情况;
  • ( 4 ) (4) (4) 计算结果数组;

五、推荐专栏

💜《夜深人静写算法》💜
二)动态规划入门

六、习题练习

序号题目链接难度
1飞机座位分配概率★☆☆☆☆
2LCP 11. 期望个数统计★★☆☆☆
3用 Rand7() 实现 Rand10()★★☆☆☆
4大样本统计★★☆☆☆
5n个骰子的点数★★★☆☆
6(困难) 新21点★★★★☆
7(困难) 两个盒子中球的颜色数相同的概率★★★★☆
👇🏻 关注公众号 观看 精彩学习视频👇🏻

以上是关于《算法零基础100讲》(第30讲) 概率与统计的主要内容,如果未能解决你的问题,请参考以下文章

题解《算法零基础100讲》(第18讲) 线性枚举 - 统计法入门(java版)

《算法零基础100讲》(第61讲) 前缀和 二维前缀和

《算法零基础》第18讲:线性枚举- 统计法入门

《算法零基础100讲》(第3讲) 矩阵

《算法零基础100讲》(第26讲) 字符串算法 - 回文串

《算法零基础100讲》(第25讲) 字符串算法 - 字符串反转