TOP-K问题解决思路:
TOP-K问题解决思路:
1.排序,选取前n个数(或后n个数)
2.bfprt算法
1.通过排序算法:最好的时间复杂度为O(nlogn),除非选用基数排序,用极多空间换时间的就不说啦。其实原因很简单,你需要的是最大的k个数,而排序是将所有数排序再选取前n个数,这时想想如果能找到第n大的数,就能找到所有小于它的数。
2.bfprt算法:
(1)将数组分为n/5(不够5的进1)组,对于每一组取中位数。(若元素数为偶数个,则取中间靠前那个)
(2)递归地使用第一步将取得的中位数再取中位数,直到剩下最后一个中位数。
(3)将数组中小于该中位数的数移到它之前,大于该中位数的移到它之后,并返回此时中位数在数组中的位置index。(类似于快速排序的partion)
(4) 如果index == k ,则该中位数就是第k大的元素
如果index < k ,则第k大的元素下标一定大于index,递归求index之后的数组
如果index > k,则第k大的元素下标一定小于index,递归求index之前的数组
Java代码:
<1>bfprt代码:(因为需要递归,参数中还有起始下标l和结束下标r)
public static int bfprt(int[] a,int l,int r,int k) {
int mid = findMid(a,l,r);
int index = findIndex(a,mid);
int i = partion(a,l,r,mid,index);
if (i == k) return a[i];
if (i > k) return bfprt(a,l,i,k);
return bfprt(a,i+1,r,k);
}
<2>findMid:寻找中位数的递归算法
public static int findMid(int[] a,int l,int r) {
if (l==r) return a[l];
int size = (r-l+1)/5 + ((r-l+1)%5==0?0:1);
int[] b = new int[size];
int bindex = 0;
int i = l;
for (;i < (r-l+1)/5*5 ; i += 5) {
快速排序.Solution.quicksort(a, i, i+4);
b[bindex++] = a[i+2];
}
if ((r-l+1)%5!=0) {
快速排序.Solution.quicksort(a, i, r);
b[bindex] = a[(i+r)/2];
}
return findMid(b,0,size-1);
}
<3>findIndex:返回该中位数在数组中的位置(便于在partion操作中进行交换)
public static int findIndex(int[] a,int num) {
for (int i = 0 ; i < a.length ; i ++) {
if (a[i] == num) return i;
}
return -1;
}
<4>partion:将数组分区(小于该中位数的置于前,大于等于该中位数的置于后)
public static int partion(int[] a,int l,int r,int mid,int index) {
a[l] = a[l] ^ a[index] ^ (a[index] = a[l]);
int i = l;
int j = r;
while (i < j) {
while (i<j&&a[j]>=mid) j--;
a[i] = a[j];
while (i<j&&a[i]<mid) i++;
a[j] = a[i];
}
a[i] = mid;
return i;
}
<5>上述代码所求出的是第k大的值,要输出前k大的数只需一次时间复杂度为O(n)的遍历即可。