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

两个问题互相可以转化。如果可以找到第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);
	else
		return 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,该如何处理?不知道。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值