算法_02_BFPRT

来源:互联网 发布:竞彩预测软件 编辑:程序博客网 时间:2024/06/05 09:08

问题:

求一个数组中第 k 小的数。
要求:时间复杂度 严格O(N)

分析:
如果把数组进行排序,然后取出第 k 个数,那么复杂度为 O(NlogN)
这种方法不行。
那么下面给出两种解答方法,第二种就是今天讲的 BFPRT。

  1. 经典解法

    • 利用快排 patition 划分
    • 然后把比划分值小的放在左边,等于放中间,大于放右边,如果 k 在等于里面,那么命中了,如果没命中,重新划分,循环……

这种解法的缺点是什么呢,在于划分值得选取。所以 BFPRT 方法与经典解法的不同之处就在于划分值得选取。

  1. BFPRT

思路:

选择中位数组中的上中位数作为划分值。

具体实现:

  • 假设整个实现为函数 int f(int[] arr, int k),返回值即为最后答案
  • 先划分5个值为一组,每一组组内排序,每组内排序为常数级别,复杂度 O(1),有 N/5组,故,总的复杂度 O(N)
  • 选择每一组中的上中位数,组成新的数组 newArr,数组长度为 N/5
  • 调用自己,int m = f(newArr, N/10),即找到中位数组中的中位值m,这个值即为划分值。

下面分析为啥是这样的,看课堂上的手写笔记吧:
长度为 N/5的 newArr 中,至少有 N/10的数比 m 小,
纵观所有数字,每5个一小组中,至少有两个数字比当初选择组成newArr 的那个值要小,那么这个数组中至少有3N/10个数字比 m 小,至多有7N/10个数字比 m 大。
同理,至少有3N/10个数字比 m 大,至多有7N/10个数字比 m 小。

也就是选择 m 作为划分值导致的结果是:比 m 大的和比 m 小的数都控制在3N/10~7N/10的范围内。
后续,要么对左边进行寻找,要么在右边进行寻找,那么就保证了,这种算法每次至少淘汰了3N/10个数字。

下面是潦草的笔记:

这里写图片描述