寻找无序数组中的第K大数和前K大数

来源:互联网 发布:牛头701在淘宝上叫什么 编辑:程序博客网 时间:2024/05/16 17:08

两个问题互相可以转化。如果可以找到第K大数,那么只再需要O(N)就可以找齐剩余的前K大数。如果可以找到前K大数,那么只再需要O(K)就可以找到第K大数。


先排序,在找第K个。O(NlgN)


快速排序的思想,可以做到平均效率O(N)

随机选一个元素,把所有小于等于这个元素的数移到左边,所有大于这个元素的数移动到右边。如果这个元素成了第K个数,直接返回这个数。

如果左边的个数大于K,不管右边的数了,在左边重复上面的过程。

如果左边的个数等于T<K,不管左边的数了,重复上面的过程,只是K=K-T-1。


平均情况下,第一次划分的时间复杂度是O(N),第二次是O(N/2),总共是O(N+N/2+N/4+...)=O(N)

#include "stdio.h"#include "stdlib.h"using namespace std;const int INCORRECT=-1;int FindKth(int d[], int left, int right, int k){if(left>right)return INCORRECT;else if(left==right&&k!=1) return INCORRECT;else if(left==right&&k==1) return d[left];else if(k>right-left+1) return INCORRECT;int num=d[left];int start=left,end=right;while(start<end){while(start<end&&d[end]>num) end--;d[start]=d[end];while(start<end&&d[start]<=num) start++;d[end]=d[start];}d[start]=num;int move = start-left + 1;if(move==k)return d[start];else if(move<k)return FindKth(d,start+1,right,k-move);elsereturn FindKth(d,left,start-1,k);}int main(){int data[10]={1,31,4,52,6,4,77,41,62,94};printf("%d\n",FindKth(data,0,9,9));}
所以上对于两个问题,理论复杂度都可以做到O(N)。


不过实际上,可能存在数组非常巨大,读取的次数越少越好。如果K比较小,可以用priority queue来存储前K的数。这样只需要读取一遍数组就可以,复杂度是O(N+N*lgK)。


如果N非常巨大,且K=N/2,该如何处理?不知道。