[解题报告]《算法零基础100讲》(第30讲) 概率与统计

目录

零、写在前面

一、主要知识点

   1.动态规划

二、课后习题 

1227. 飞机座位分配概率

LCP 11. 期望个数统计

470. 用 Rand7() 实现 Rand10()

 1093. 大样本统计

剑指 Offer 60. n个骰子的点数

837. 新21点837. 新21点https://leetcode-cn.com/problems/new-21-game/

1467. 两个盒子中球的颜色数相同的概率

写在最后


零、写在前面

        今天是打卡的第30天,其实平心而论,今天的难度是不算高的。知识点在:
《算法零基础100讲》(第30讲) 概率与统计https://blog.csdn.net/WhereIsHeroFrom/article/details/121414040https://blog.csdn.net/WhereIsHeroFrom/article/details/121414040


一、主要知识点

   1.动态规划

blablabla。。。。。看题吧,实在没啥知识点了-.-


二、课后习题 

1227. 飞机座位分配概率

1227. 飞机座位分配概率https://leetcode-cn.com/problems/airplane-seat-assignment-probability/

题目描述

有 n 位乘客即将登机,飞机正好有 n 个座位。第一位乘客的票丢了,他随便选了一个座位坐下。

剩下的乘客将会:

如果他们自己的座位还空着,就坐到自己的座位上,

当他们自己的座位被占用时,随机选择其他座位
第 n 位乘客坐在自己的座位上的概率是多少?

思路

1.假如第一位直接坐在第一个 那么n必然坐在自己的位置上

2.假如第一位坐在第n个  那么n必然不坐在自己的位置上

3.假如第一位坐在第i个位置,那么就相当于第i个人随便找一个位置,第n坐在自己位置上的概率

可以得到概率公式F(n) = \frac{1}{n} \times 1+\frac{1}{n} \times 0+\frac{1}{n} \times \sum_{i=2}^{n-1}F(n-i+1)

再坐下化简 F(n-1) = \frac{1}{n-1} \times 1+\frac{1}{n-1} \times \sum_{i=2}^{n-2}F(n-i)

最终得到 nF(n)+(n-1)F(n-1)=F(n-1)

也就是F(n) =F(n-1)就是除了1全是1/2呗?

double nthPersonGetsNthSeat(int n){
    return n == 1?1.0:0.5;
}

LCP 11. 期望个数统计

LCP 11. 期望个数统计https://leetcode-cn.com/problems/qi-wang-ge-shu-tong-ji/

题目描述

某互联网公司一年一度的春招开始了,一共有 n 名面试者入选。每名面试者都会提交一份简历,公司会根据提供的简历资料产生一个预估的能力值,数值越大代表越有可能通过面试。

小 A 和小 B 负责审核面试者,他们均有所有面试者的简历,并且将各自根据面试者能力值从大到小的顺序浏览。由于简历事先被打乱过,能力值相同的简历的出现顺序是从它们的全排列中等可能地取一个。现在给定 n 名面试者的能力值 scores,设 X 代表小 A 和小 B 的浏览顺序中出现在同一位置的简历数,求 X 的期望。

思路

如果能力值不同 一定是不同的 那么如果能力值相同呢?主要问题在这里

假如有n个相同的元素 假设第一个位置相同的概率就是1/n

那么总的E(X) = E(x1)*1/n+....=1

对,没错就是1.。。那么一切问题就简单了。统计有多少不同值元素不就好了,hash表。

int expectNumber(int* scores, int scoresSize){
    int hash[1000001],len = 0;
    for(int i = 0;i < scoresSize;i++)//hash初始化
        hash[scores[i]] = 0;
    for(int i = 0;i < scoresSize;i++)
        if(!hash[scores[i]]) hash[scores[i]] = 1,len++;//统计元素
    return len;
}

470. 用 Rand7() 实现 Rand10()

470. 用 Rand7() 实现 Rand10()https://leetcode-cn.com/problems/implement-rand10-using-rand7/

题目描述

已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。

不要使用系统的 Math.random() 方法。

思路

我们可以用两次rand7生成1-49的数字 就是(rand7-1)*7+rand7;

但是我们需要生成的是1-10,那么我们只取10-49这40个数字就好了。然后我们把它-6/4就能得到1-10。

int rand10() {
    int a;
    while(1){
        a = (rand7()-1)*7 + rand7();
        if(a<10)   continue;//抛弃重随
        else{
            a = (a-6)/4;//修改映射
            break;
        } 
    }
    return a;
}

 1093. 大样本统计

1093. 大样本统计https://leetcode-cn.com/problems/statistics-from-a-large-sample/

题目描述

我们对 0 到 255 之间的整数进行采样,并将结果存储在数组 count 中:count[k] 就是整数 k 的采样个数。

我们以 浮点数 数组的形式,分别返回样本的最小值、最大值、平均值、中位数和众数。其中,众数是保证唯一的。

思路

这题不配叫做中等题。。。就按照定义求就完事了,能有啥技巧。

不过。。。平均数会溢出 我转成了long long

double* sampleStats(int* count, int countSize, int* returnSize){
    double *ans = malloc(sizeof(double)*5);
    ans[0] = 257;ans[1]=0;ans[2] = 0;
    double zhongwei = 1;
    int zhongshu = 1;
    int size = 0;
    *returnSize = 5;
    for(int i = 0;i<countSize;i++){
        if(count[i]){
            if(i>ans[1]) ans[1] = i;//最大值
            if(i<ans[0]) ans[0] = i;//最小值
            ans[2] += (long long)i*count[i];
            size += count[i];        //统计个数
            if(count[i]>count[zhongshu])    zhongshu = i;//统计众数
        }
    }
    ans[2] /= size;     //平均数
    //中位数求解
    if(size&1 == 1){
        int j = 0;
        for(int i = 0;i<=size/2;){
            i+=count[j++];
        }
        zhongwei = j-1;
    }
    else{
        int i,j=0;
        for(i = 0;i<size/2;){
            i+=count[j++];
        }
        if(i>=size/2+1) zhongwei = j-1;
        else {
            zhongwei = j-1;
            printf("%d ",j);
            while(i<size/2+1)   i+=count[j++];
            printf("%d ",j);
            zhongwei += j-1;
            zhongwei/=2;
        }
    }
    ans[3] = zhongwei;
    ans[4] = zhongshu;
    return ans;
}

剑指 Offer 60. n个骰子的点数

剑指 Offer 60. n个骰子的点数https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/

题目描述

把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。

你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。

思路

其实这道题很动态规划0.0

我们很容易知道第i次的点数范围是 i - 6*i;

考虑第i-1次 也就是前一次的点数,我们知道第i次掷色子只能是1-6 并且等可能都是1/6

那么假如第i-1次掷到了8那么可以为第i次之后掷色子的 9 、 10 、11 、12 、13 、14这六个数字贡献概率也也就是我们可以遍历第i-1次所有的结果概率得到第i次的概率

double* dicesProbability(int n, int* returnSize){
    double *ans = malloc(sizeof(double)*6*n);
    for(int i = 0;i < 6;i++)    ans[i] = 1.0/6.0;
    for(int i = 2;i <= n;i++){
        double temp[i*5+1];    //临时数组
        for(int j=0;j<i*5+1;j++)    temp[j] = 0.0;
        for(int j = 0;j<i*5-4;j++)
            for(int k = 0;k<6;k++)
                temp[j+k] += ans[j]/6;//计算第i次的概率分布
        for(int j = 0;j<i*5+1;j++)//计算第i次的概率分布
            ans[j] = temp[j];
    }
    *returnSize = n*5+1;//i - 6*i 一共有5*i+1个数字
    return ans;
}

837. 新21点
837. 新21点https://leetcode-cn.com/problems/new-21-game/

题目描述

爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:

爱丽丝以 0 分开始,并在她的得分少于 K 分时抽取数字。 抽取时,她从 [1, W] 的范围中随机获得一个整数作为分数进行累计,其中 W 是整数。 每次抽取都是独立的,其结果具有相同的概率。

当爱丽丝获得不少于 K 分时,她就停止抽取数字。 爱丽丝的分数不超过 N 的概率是多少?

思路

其实这道题和上面那道题的思路有点像。

我们要求的是F(0)

但是我们知道F(K)-F(K+W)的值 因为[F(k) , F(N)] = 1 然后大于N概率就是0

逆向一下 我们可以知道F(K-1)的值 因为 F(k-1) = 1/W*F(K)+....1/W*F(K+W-1)

根据这种递推关系 我们就可以退出来F(0)

为了加快速度,,,不然超时,我们可以用一个sum保存当前计算元素的前W项的和

double new21Game(int n, int k, int maxPts){
    double dp[k+maxPts],sum = 0;
    for(int i = k;i < k+maxPts;i++)      //初始化最前端的位置
        if(i <= n)   dp[i] = 1.0,sum+=1.0;
        else dp[i] = 0.0;;
    for(int i = k -1;i>=0;i--){//递归计算
        dp[i] = sum/maxPts;
        sum = sum - dp[i+maxPts] + dp[i];
    }
    return dp[0];//返回
}

1467. 两个盒子中球的颜色数相同的概率

1467. 两个盒子中球的颜色数相同的概率https://leetcode-cn.com/problems/probability-of-a-two-boxes-having-the-same-number-of-distinct-balls/

题目描述

桌面上有 2n 个颜色不完全相同的球,球上的颜色共有 k 种。给你一个大小为 k 的整数数组 balls ,其中 balls[i] 是颜色为 i 的球的数量。

所有的球都已经 随机打乱顺序 ,前 n 个球放入第一个盒子,后 n 个球放入另一个盒子(请认真阅读示例 2 的解释部分)。

思路

其实就是算将2n个球分为两堆 两堆颜色数目相同的概率

全集我们很容易知道 就是C\binom{n}{2*n} 可以拆解为\prod_{1}^{n}\frac{(n+i)}{i}

然后符合条件的元素我们就需要进行拆解先看第一个球 我们就可以拆解成

C\binom{0}{k}F(1,-k,-1)+C\binom{1}{k}F(1,-k+1,0)+...+C\binom{k}{k}F(1,k,1)

然后我们就可以递归调用 直到F中第一个参数等于n判断是否满足条件即可

为了加速 我们做两个小改动

1.用left数组保存剩余球数目,如果剩余球的数目小于两个袋子球数之差就直接返回

2.提前计算阶乘加速计算排列数

int left[8];
int n = 0;
long long f[11] = {1,1,2,6,24,120,720,5040,40320,362880,3628800};   //阶乘
int combination(int a,int b){
    return f[b]/(f[a]*f[b-a]);
}
double dfs(int* balls,int m,int leftnum,int leftcol){//m为递归深度 也就是第几种颜色 leftnum表示前一个口袋比后一个口袋多多少球 leftcol表示前一个口袋比后一个口袋多多少颜色
    if(m == n)        
        return leftnum ==0 && leftcol == 0;//保证球数差为0且颜色差为0
    if(abs(leftnum) > left[m])    //始终无法满足 直接跳出
        return 0;
    double ans = 0;
    for(int i = 0;i <= balls[m];i++){    //计算所有情况
        int color = (i == 0) ? -1 : (i == balls[m] ? 1 : 0);//简单来说 i为0的时候颜色差为负数,i为最大值的时候颜色差为正数 其他时候为0 因为每个口袋都分到这种颜色的球了
        ans += (combination(i,balls[m]))*dfs(balls,m + 1,leftnum +i - (balls[m] - i),leftcol + color);
    }
    return ans;
}
double getProbability(int* balls, int ballsSize){
    n = ballsSize;
    int sum = 0;
    for(int i = 0;i < n;i++)//计算总数
        sum += balls[i];
    left[n-1] = balls[n-1];//初始化剩余球数
    for(int i = n - 2;i >= 0;i--)
        left[i] = balls[i] + left[i + 1];
    double q = 1.0;
    for(int i = 1;i <= sum/2;i++)
        q *= (sum/2 + i)*1.0/i;//计算C(n,2*n)
    return dfs(balls,0,0,0)/q;
}

写在最后

今天看了英雄哥的话感觉受益匪浅,卷完这周的刷题,下周我就要有安排的补充知识点了,慢慢的形成体系,当然需要先有量暴露问题,然后才能更有针对性的解决。我看好多人都很迷茫,其实就是先去尝试做些事情,做着做着才能发现问题,才能思考怎么取改进,只是迷茫是没有任何帮助的,好了,大家加油呀!

猜你喜欢

转载自blog.csdn.net/qq_17593855/article/details/121432310
今日推荐