• Top k问题的讨论(三种方法的java实现及适用范围)


    在很多的笔试和面试中,喜欢考察Top K.下面从自身的经验给出三种实现方式及实用范围。

    • 合并法

        这种方法适用于几个数组有序的情况,来求Top k。时间复杂度为O(k*m)。(m:为数组的个数).具体实现如下:

    /**
    * 已知几个递减有序的m个数组,求这几个数据前k大的数
    *适合采用Merge的方法,时间复杂度(O(k*m);
    */
    import java.util.List;
    import java.util.Arrays;
    import java.util.ArrayList;
    public class TopKByMerge{
     public int[] getTopK(List<List<Integer>>input,int k){
        int index[]=new int[input.size()];//保存每个数组下标扫描的位置;
        int result[]=new int[k];
        for(int i=0;i<k;i++){
           int max=Integer.MIN_VALUE;
           int maxIndex=0;
           for(int j=0;j<input.size();j++){
               if(index[j]<input.get(j).size()){
                    if(max<input.get(j).get(index[j])){
                        max=input.get(j).get(index[j]);
                        maxIndex=j;
                    }
               }
           }
           if(max==Integer.MIN_VALUE){
               return result;
           }
           result[i]=max;
           index[maxIndex]+=1;
           
        }
        return result;
     } 
    •  快排过程法

        快排过程法利用快速排序的过程来求Top k.平均时间复杂度为(O(n)).适用于无序单个数组。具体java实现如下:

    /*
    *利用快速排序的过程来求最小的k个数
    *
    */
    public class TopK{
       int partion(int a[],int first,int end){
            int i=first;
            int main=a[end];
            for(int j=first;j<end;j++){
                 if(a[j]<main){
                    int temp=a[j];
                    a[j]=a[i];
                    a[i]=temp;
                    i++;
                 }
            }
            a[end]=a[i];
            a[i]=main;
            return i;    
       }
       void getTopKMinBySort(int a[],int first,int end,int k){
          if(first<end){
              int partionIndex=partion(a,first,end);
              if(partionIndex==k-1)return;
              else if(partionIndex>k-1)getTopKMinBySort(a,first,partionIndex-1,k);
              else getTopKMinBySort(a,partionIndex+1,end,k);
          }
       }
    public static void main(String []args){
          int a[]={2,20,3,7,9,1,17,18,0,4};
          int k=6;
          new TopK().getTopKMinBySort(a,0,a.length-1,k);
          for(int i=0;i<k;i++){
             System.out.print(a[i]+" ");
          }
       }
    }
    • 采用小根堆或者大根堆

       求最大K个采用小根堆,而求最小K个采用大根堆。

      求最大K个的步奏:

    1.     根据数据前K个建立K个节点的小根堆。
    2.     在后面的N-K的数据的扫描中,
    • 如果数据大于小根堆的根节点,则根节点的值覆为该数据,并调节节点至小根堆。
    • 如果数据小于或等于小根堆的根节点,小根堆无变化。

     求最小K个跟这求最大K个类似。时间复杂度O(nlogK)(n:数据的长度),特别适用于大数据的求Top K。

    /**
     * 求前面的最大K个 解决方案:小根堆 (数据量比较大(特别是大到内存不可以容纳)时,偏向于采用堆)
     * 
     * 
     */
    public class TopK {
        /**
         * 创建k个节点的小根堆
         * 
         * @param a
         * @param k
         * @return
         */
        int[] createHeap(int a[], int k) {
            int[] result = new int[k];
            for (int i = 0; i < k; i++) {
                result[i] = a[i];
            }
            for (int i = 1; i < k; i++) {
                int child = i;
                int parent = (i - 1) / 2;
                int temp = a[i];
                while (parent >= 0 &&child!=0&& result[parent] >temp) {
                    result[child] = result[parent];
                    child = parent;
                    parent = (parent - 1) / 2;
                }
                result[child] = temp;
            }
            return result;
    
        }
    
        void insert(int a[], int value) {
             a[0]=value;
             int parent=0;
             
             while(parent<a.length){
                 int lchild=2*parent+1;
                 int rchild=2*parent+2;
                 int minIndex=parent;
                 if(lchild<a.length&&a[parent]>a[lchild]){
                     minIndex=lchild;
                 }
                 if(rchild<a.length&&a[minIndex]>a[rchild]){
                     minIndex=rchild;
                 }
                 if(minIndex==parent){
                     break;
                 }else{
                     int temp=a[parent];
                     a[parent]=a[minIndex];
                     a[minIndex]=temp;
                     parent=minIndex;
                 }
             }
             
        }
    
        int[] getTopKByHeap(int input[], int k) {
            int heap[] = this.createHeap(input, k);
            for(int i=k;i<input.length;i++){
                if(input[i]>heap[0]){
                    this.insert(heap, input[i]);
                }
            
                
            }
            return heap;
    
        }
    
        public static void main(String[] args) {
            int a[] = { 4, 3, 5, 1, 2,8,9,10};
            int result[] = new TopK().getTopKByHeap(a, 3);
            for (int temp : result) {
                System.out.println(temp);
            }
        }
    }
  • 相关阅读:
    新手小白如何购买阿里云服务器?
    nginx 泛域名解析 实现 多域名动态网站内容
    CentOS 安装MySQL 详细教程
    CentOS添加并挂载新硬盘
    docker下nginx+tomcat 文件的上传与访问
    关于人人开源renren-fast-vue 中npm install各种报错的解决方案
    《素面朝天,青春盛宴》
    手把手教你springboot中导出数据到excel中
    使Word文档和PDF文件不可被复制的方法
    博客园中使用MarkDown编辑器向博文中添加视频
  • 原文地址:https://www.cnblogs.com/big-sun/p/4085793.html
Copyright © 2020-2023  润新知