BFPRT算法

题目:给你一个无序整型数组,返回其中第K小的数。

法一、暴力解:排序解决 O(N*logN)
在这里插入图片描述
这道题可以利用荷兰国旗改进的 partition 和随机快排的思想:随机选出一个数,将数组以该数作比较划分为:<,=,> 三个部分,则可得知 = 部分的数是数组中第几小的数,接着对 < (如果第K小的数在 < 部分)或> (如果第K小的数在 > 部分)部分的数递归该过程,**直到 = 部分的数正好是整个数组中第K小的数。**这种做法不难求得时间复杂度的数学期望为 O(NlogN) (以2为底)。但这毕竟是数学期望,在实际工程中的表现可能会有偏差

而BFPRT算法能够做到时间复杂度就是 O(NlogN)

具体做法:BFPRT算法首先将数组按5个元素一组划分成 N/5 个小部分(最后不足5个元素自成一个部分),再这些小部分的内部进行排序,然后将每个小部分的中位数取出来再排序得到中位数。(最后一组 若是偶数,则取 上中位数,也可以取下 中位数)
5 个数 组内排序:代价O(1)。
N/5 个组,代价O(N)

当然,不仅仅只能5个数分,还可以3个,7个等等。
在这里插入图片描述
BFPRT求解此题的步骤和开头所说的步骤大体类似,但是 “随机选出一个的作为比较的那个数” 这一步替换为上图所示最终选出来的那个数。

O(NlogN) 的证明,为什么每一轮 partition 中的随机选数改为BFPRT定义的选数逻辑之后,此题的时间复杂度就彻底变为 O(NlogN) 了呢?下面分析一下这个算法的步骤:

BFPRT算法,接收一个数组一个K值,返回数组中的一个数
即,在这个数组中,找到第K小的数,并返回。

  1. 数组被划分为了 N/5 个小部分,每个部分的5个数排序需要 O(1) ,所有部分排完需要 O(N/5)=O(N)
  2. 取出每个小部分的中位数,一共有 N/5 个,递归调用BFPRT算法得到这些数中第 (N/5)/2 小的数(即这些数的中位数),记为 pivot
  3. 以 pivot 作为比较,将整个数组划分为 <pivot , =pivot , >pivot 三个区域
  4. 判断第K小的数在哪个区域,如果在 = 区域则直接返回 pivot ,如果在 < 或 > 区域,则将这个区域的数递归调用BFPRT算法
  5. base case :在某次递归调用BFPRT算法时发现这个区域只有一个数,那么这个数就是我们要找的数。

每个数组 最中间的数组成原数组:
在这里插入图片描述
在N/5个数组中,有 N/10 个数 比他大。(中位数嘛)
在这里插入图片描述
时间复杂度为 O(NlogN) (底数为2)的证明,分析 bfprt 的执行步骤(假设 bfprt 的时间复杂度为 T(N) ):

  1. 首先数组5个5个一小组并内部排序,对5个数排序为 O(1) ,所有小组排好序为 O(N/5)=O(N)
  2. 由步骤1的每个小组抽出中位数组成一个中位数小组,共有 N/5 个数,递归调用 bfprt 求出这 N/5 个数中
    第 (N/5)/2 小的数(即中位数)为 T(N/5) ,记为 pivot
  3. 对步骤2求出的 pivot 作为比较将数组分为小于、等于、大于三个区域,由于 pivot 是中位数小组中的中位
    数,所以中位数小组中有 N/5/2=N/10 个数比 pivot 小,这 N/10 个数分别又是步骤1中某小组的中位数,
    可推导出至少有 3N/10 个数比 pivot 小,也即最多有 7N/10 个数比 pivot 大。也就是说,大于区域(或小于)最大包含 7N/10 个数、最少包含 3N/10 个数,那么如果第 i 大的数不在等于区域时,无论是递归bfprt 处理小于区域还是大于区域,最坏情况下子过程的规模最大为 7N/10 ,即 T(7N/10)。
    综上所述, bfprt 的 T(N) 存在推导公式: T(N/5)+T(7N/10)+O(N) 。根据 基础篇 中所介绍的Master公式可以
    求得 bfprt 的时间复杂度就是 O(NlogN) (以2为底)。

举个例子:

有10个班(每班50人,总数N=5*100=500),每个班取成绩排名中间的人 作为代表(代表 有10个人,即N/10)。

我正好在10个人的 中间,那么10个班中,至少比我成绩高的人数有:(一定注意是至少!!,实际人数可能更多,如下图)

总共有5个人 (N/20) 比我成绩高,等他们回到各自的班级后,共有 5× 25 +25 个人比我成绩好!(即6×25,即3×N/10)

在这里插入图片描述
时间复杂度分析:
在这里插入图片描述
应用:
在数组中找出最大的(最小的)前 k 个数

注意:要是每组 个数不是5,而是3,则

T(N)=T(N/3)+T(2N/3)+O(N),且其可以收敛到O(N)

选三个数,七个数作为一组,均可以收敛到O(N)

如果T(N) 最后的表达式 不能收敛到 O(N) ,则不能选此划分值,而5,7作为划分值时,正好可以收敛到 O(N) !

代码
在这里插入图片描述

进阶二 12:27 开始

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值