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(k*logn).适用于无序单个数组。具体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);
        }
    }
}
时间: 2024-10-23 18:03:28

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

JAVA写JSON的三种方法,java对象转json数据

转自:http://www.xdx97.com/#/single?bid=5afe2ff9-8cd1-67cf-e7bc-437b74c07aef 原文地址:https://www.cnblogs.com/jasonboren/p/10632997.html

让一个元素垂直水平居中的三种方法

第一种方法: div.box{ weight:200px; height:400px; <!--把元素变成定位元素--> position:absolute; <!--设置元素的定位位置,距离上.左都为50%--> left:50%; top:50%; <!--设置元素的左外边距.上外边距为宽高的负1/2--> margin-left:-100px; margin-top:-200px; } *兼容性好;缺点:必须知道元素的宽高 ------------- 第二种方法:

Javascript定义类(class)的三种方法

注:本文转自阮一峰,觉得此篇文章对我对大家有帮助,因此转过来. 将近20年前,Javascript诞生的时候,只是一种简单的网页脚本语言.如果你忘了填写用户名,它就跳出一个警告. 如今,它变得几乎无所不能,从前端到后端,有着各种匪夷所思的用途.程序员用它完成越来越庞大的项目.Javascript代码的复杂度也直线上升.单个网页包含10000行Javascript代码,早就司空见惯.2010年,一个工程师透露,Gmail的代码长度是443000行! 编写和维护如此复杂的代码,必须使用模块化策略.目

CSS实现导航条Tab切换的三种方法

前面的话 ??导航条Tab在页面中非常常见,本文说详细介绍CSS实现导航条Tab的三种方法 布局 ??根据上图所示,先规定几个定义,上图的模块整体叫做导航,由导航标题和导航内容组成.要实现上图所示的布局效果,有两种布局方法:语义布局和视觉布局 [语义布局] ??从语义布局的角度来看,每一个导航标题和其对应的导航内容应该是一个整体 <style> body,p{margin: 0;} h2{margin: 0;font-size:100%;} ul{margin: 0;padding: 0;li

让一个元素垂直水平居中的三种方法【转】

第一种方法: div.box{ weight:200px; height:400px; <!--把元素变成定位元素--> position:absolute; <!--设置元素的定位位置,距离上.左都为50%--> left:50%; top:50%; <!--设置元素的左外边距.上外边距为宽高的负1/2--> margin-left:-100px; margin-top:-200px; } *兼容性好;缺点:必须知道元素的宽高 ------------- 第二种方法:

三种方法求解约瑟夫环问题

约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又出列:依此规律重复下去,直到圆桌周围的人全部出列. 方法1:使用stl::list模拟环形链表,参考剑指offer 代码: #include <iostream> #include <list> using namespace std; int lastNumber(unsigned int n,un

js之二维数组定义和初始化三种方法

方法一:直接定义并且初始化,这种遇到数量少的情况可以用 var _TheArray = [["0-1","0-2"],["1-1","1-2"],["2-1","2-2"]] 方法二:未知长度的二维数组 var tArray = new Array();   //先声明一维 for(var k=0;k<i;k++){        //一维长度为i,i为变量,可以根据实际情况改变

关于上一篇鼠标移到按钮时的“按下”效果的三种方法

上一篇博文中,关于按钮按下的效果回过头研究了下,总结了如下三种方法,只写出关键样式: 1.相对定位 1 input.button{ 2 3 position:relative; //用相对定位 4 } 5 6 input.button:hover{ 7 top:2px;//鼠标移动到此top增加2px 8 } 2.主要利用外边距这个属性,鼠标移动到按钮位置时,按钮上外边距增加2px,下外边距减少2px(相当于走出去2px又退回来2px),就可以达到按下效果,如果只是单独写margin-top:2

jquery 点击显示隐藏的三种方法

jquery点击显示隐藏的三种方法,从复杂到简单.使用jquery需要引用jquery库,如右所示<script src="jquery-1.11.3.min.js"type="text/javascript"></script>. 旁边按钮随着收缩展开发生状态变化,展开+变—,收缩—变+. 收缩效果: 展开效果: 一.HTML结构(盗用网上的) <body> <!-- 收缩展开效果 --><li class=&