TopK问题有几种解决办法?
指定n个数字,找出其中最大的k个数,这就是经典的TopK问题
解决方法一:全局排序将n个数进行全排序,取出最大的k个,即是所需的结果代码:public int[] topK(int[] array, int k) { Arrays.sort(array); return Arrays.copyOfRange(array, array.length - k, array.length);}
时间复杂度是O(N*logN)解决方法二:局部排序其实没有必要将所有的元素都排序,只需要将前k个最大的值排序出来就可以停止排序,得到的k个值就是需要的结果代码
public int[] topK(int[] array, int k) { for(int i = 0; i < k; i++) { for(int j = array.length - 1; j > 0; j--) { if(array[j] > array[j - 1]) { int tmp = array[j]; array[j] = array[j - 1]; array[j - 1] = tmp; } } }}
时间复杂度是O(k*N)解决方法三:堆构建一个k大小的小堆,先将前k个元素放入堆中,然后遍历剩下的元素,如果大于堆顶的元素,就和堆顶的元素进行交换,遍历结束后,得到的堆上的值就是前k个最大的值代码
public Integer[] topK(int[] array, int k) { PriorityQueue<Integer> queue = new PriorityQueue<>(); for(int i = 0; i < k; i++) { queue.add(array[i]); } for(int i = k; i < array.length; i++) { if(array[i] > queue.peek()) { queue.poll(); queue.add(array[i]); } } return (Integer[])queue.toArray();}
时间复杂度:O(N*logK)解决方法四:随机选择使用减治的的思想,制定一个元素flag将比flag大的元素放在他左边,比他小的放在他右边如果flag的的下标index比k大说明前k个大的元素都在flag左边的区间,然后在他左区间内重复第一步直到找到下标为k的值如果flag的下标index比k小说明只要在他的右区间内重复第一步找到下标为k-index的值找到第k个大的值后再进行此一步骤,它左边的所有的元素就是前k个最大的值
代码:
public int[] topK5(int[] array, int k) { int left = 0; int right = array.length - 1; //因为数组下标是以0开始的,因此第k个的小标为k - 1,因此传入的为k - 1 int flag = RS(array, left, right, k - 1); //返回值flag为第k个最大值的下标,因此需要前k个最大的值时,拷贝数组的范围是[0, flag + 1) return Arrays.copyOfRange(array, 0, flag + 1));}private int RS(int[] array, int left, int right, int k) { if (left >= right) { return left; } int index = partition(array, left, right); int temp = index - left; if(temp >= k) { return RS(array, left, index - 1, k); } else { return RS(array, index + 1, right, k - index); }}private int partition(int[] array, int left, int right) { int tmp = array[left]; int l = left; int r = right; while(l < r) { while(l < r && array[r] <= tmp) { r--; } array[l] = array[r]; while(l < r && array[l] >= tmp) { l++; } array[r] = array[l]; } array[l] = tmp; return l;}
时间复杂度:O(N)
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。