码迷,mamicode.com
首页 > 其他好文 > 详细

解决TopK问题的方式

时间:2020-02-18 09:44:51      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:步骤   问题   结果   描述   元素   priority   oar   topk   拷贝   

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)

解决TopK问题的方式

标签:步骤   问题   结果   描述   元素   priority   oar   topk   拷贝   

原文地址:https://blog.51cto.com/14233687/2471821

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!