17、【常见算法】topN问题

题    目:如果在N个数中找出其中前K大的数?

思路一:

  先对N个数进行排序,然后在取其前K大的数;(冒泡排序,快速排序等)

思路二:

  部分排序,只排除前K大的数即可(使用选择排序进行部分排序,选择排序的时间复杂度O(N2))

思路三:

  我可以用分治法,这有点类似快排中partition的操作。随机选一个数t,然后对整个数组进行partition,会得到两部分,前一部分的数都大于t,后一部分的数都小于t。

  如果说前一部分总数大于1000个,那就继续在前一部分进行partition寻找。如果前一部分的数小于1000个,那就在后一部分再进行partition,寻找剩下的数。

  该思路的事件复杂度为O(N):首先,partition的过程,时间是o(n)。我们在进行第一次partition的时候需要花费n,第二次partition的时候,数据量减半了,所以只要花费n/2,同理第三次的时候只要花费n/4,以此类推。而n+n/2+n/4+...显然是小于2n的,所以这个方法的渐进时间只有o(n)。

思路四:

  当N的值过大,且内存资源有限,无法一次读取全部数据时,可以考虑分布式的实现,将数据切分,然后在多台机器上分别计算前K大的数,最后在把这些数据汇总。

思路五:

  使用最小堆思想。即在内存中维护一个有K个数组成的最小堆;根据最小堆每一个节点都要比他的左右直接点小的性质:

  首先从N个数中取K个数构成最小堆;

  然后依次读取剩余数据,并且和堆顶元素比较大小,如果比堆顶小,则直接丢弃。如果比堆顶大,就替换堆顶,并调整最小堆;

  所有数据都处理完毕后,最小堆就是N个数中前K大的数。

  优点是:数据只需要读取一次,不会存在数据多次读写的问题;

【思路五的C++实现】

【待更新。。。。】

猜你喜欢

转载自www.cnblogs.com/Long-w/p/9831679.html