问题描述
每次给定一个数值,询问此数值以及之前给定数值中最小的n
个数
例如给定数值的顺序为:8 7 1 2 9 4
,设n == 3
8
:不足3
个数,则答案为8
7
:不足3
个数,则答案为8 7
1
:不足3
个数,则答案为8 7 1
2
:8 7 1 2
中较小的3个数为7 1 2
9
: 8 7 1 2 9
中较小的3个数为7 1 2
4
:8 7 1 2 9 4
中较小的3个数为4 1 2
暴力做法
一个最直观的方法是,每次添加新的数据后,将当前所有数据进行排序,选择较小的n个
一次排序最快也要\(O(nlogn)\),总的复杂度至少要\(O(n^2logn)\)
小根堆和大根堆
维护一个容量为n
的大根堆,堆内元素代表当前最小的n
个值
每次添加数值与堆顶元素进行比较,具有以下两种情况:
大于堆顶元素: 由于是大根堆,堆顶元素为最小的n
个数中的最大值,则此数值一定大于n个数中的其他值,即它一定不属于答案
小于堆顶元素:则用它取代堆顶元素则可以使得这n
个数更小
对于问题描述中所举的例子,使用大根堆的求解流程如下:
8
:不足3
个数,则答案为8
7
:不足3
个数,则答案为8 7
1
:不足3
个数,则答案为8 7 1
2
:2 < 8
, 则答案为7 2 1
9
: 9 > 7
,则答案不变为7 2 1
4
:4 < 7
,则答案为4 2 1
总结
动态求前n
个最小值使用大根堆
动态求前n
个最大值使用小根堆