Top K是很常见的一种问题,是指在N个数的无序序列中找出最大的K个数,而其中的N往往都特别大,对于这种问题,最容易想到的办法当然就是先对其进行排序,然后直接取出最大的K个元素就行了,但是这种方法往往是不可靠的,不仅时间效率低而且空间开销大,排序是对所有数都要进行排序,而实际上,这类问题只关心最大的K个数,并不关心序列是否有序,因此,排序实际上是浪费了的很多资源都是没必要的。
题目:
输入 n 个整数,找出其中最大的 k 个数。例如输入4、5、1、6、2、7、3、8 这8个数字,则最大的4个数字是5、6、7、8。
解法一:基于快排的O(n)的算法
如果基于数组的第 k 个数字来调整,使得比第 k 个数字小的所有数字都位于数组的左边,比第 k 个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的 k 个数字就是最小的 k 个数字(这 k 个数字不一定是排序的)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54publicclassLeastK{
publicstaticvoidgetLeastNumbers(int[]input,int[]output){
if(input==null||output==null||output.length<=0||input.length
thrownewIllegalArgumentException("Invalid args");
}
intstart=0;
intend=input.length-1;
intindex=partition(input,start,end);// 切分后左子数组的长度
inttarget=output.length-1;// K-1
// 若切分后左子数组长度不等于K
while(index!=target){// 若切分后左子数组长度小于K,那么继续切分右子数组,否则继续切分左子数组
if(index
start=index+1;
}else{
end=index-1;
}
index=partition(input,start,end);
}
System.arraycopy(input,0,output,0,output.length);
}
privatestaticintpartition(intarr[],intleft,intright){
inti=left;
intj=right+1;
intpivot=ar