Top K问题在数据分析中非常普遍的一个问题(在面试中也经常被问到),比如:

从20亿个数字的文本中,找出最大的前100个。

解决Top K问题有两种思路,

  • 最直观:小顶堆(大顶堆 -> 最小100个数);
  • 较高效:Quick Select算法。

LeetCode上有一个问题215. Kth Largest Element in an Array,类似于Top K问题。

1. 堆

小顶堆(min-heap)有个重要的性质——每个结点的值均不大于其左右孩子结点的值,则堆顶元素即为整个堆的最小值。JDK中PriorityQueue实现了数据结构堆,通过指定comparator字段来表示小顶堆或大顶堆,默认为null,表示自然序(natural ordering)。

小顶堆解决Top K问题的思路:小顶堆维护当前扫描到的最大100个数,其后每一次的扫描到的元素,若大于堆顶,则入堆,然后删除堆顶;依此往复,直至扫描完所有元素。Java实现第K大整数代码如下:

public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> minQueue = new PriorityQueue<>(k);
for (int num : nums) {
if (minQueue.size() < k || num > minQueue.peek())
minQueue.offer(num);
if (minQueue.size() > k)
minQueue.poll();
}
return minQueue.peek();
}

2. Quick Select

Quick Select [1]脱胎于快排(Quick Sort),两个算法的作者都是Hoare,并且思想也非常接近:选取一个基准元素pivot,将数组切分(partition)为两个子数组,比pivot大的扔左子数组,比pivot小的扔右子数组,然后递推地切分子数组。Quick Select不同于Quick Sort的是其没有对每个子数组做切分,而是对目标子数组做切分。其次,Quick Select与Quick Sort一样,是一个不稳定的算法;pivot选取直接影响了算法的好坏,worst case下的时间复杂度达到了\(O(n^2)\)。下面给出Quick Sort的Java实现:

public void quickSort(int arr[], int left, int right) {
if (left >= right) return;
int index = partition(arr, left, right);
quickSort(arr, left, index - 1);
quickSort(arr, index + 1, right);
} // partition subarray a[left..right] so that a[left..j-1] >= a[j] >= a[j+1..right]
// and return index j
private int partition(int arr[], int left, int right) {
int i = left, j = right + 1, pivot = arr[left];
while (true) {
while (i < right && arr[++i] > pivot)
if (i == right) break;
while (j > left && arr[--j] < pivot)
if (j == left) break;
if (i >= j) break;
swap(arr, i, j);
}
swap(arr, left, j); // swap pivot and a[j]
return j;
} private void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}

Quick Select的目标是找出第k大元素,所以

  • 若切分后的左子数组的长度 > k,则第k大元素必出现在左子数组中;
  • 若切分后的左子数组的长度 = k-1,则第k大元素为pivot;
  • 若上述两个条件均不满足,则第k大元素必出现在右子数组中。

Quick Select的Java实现如下:

public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, k, 0, nums.length - 1);
} // quick select to find the kth-largest element
public int quickSelect(int[] arr, int k, int left, int right) {
if (left == right) return arr[right];
int index = partition(arr, left, right);
if (index - left + 1 > k)
return quickSelect(arr, k, left, index - 1);
else if (index - left + 1 == k)
return arr[index];
else
return quickSelect(arr, k - index + left - 1, index + 1, right); }

上面给出的代码都是求解第k大元素;若想要得到Top K元素,仅需要将代码做稍微的修改:比如,扫描完成后的小顶堆对应于Top K,Quick Select算法用中间变量保存Top K元素。

3. 参考资料

[1] Hoare, Charles Anthony Richard. "Algorithm 65: find." Communications of the ACM 4.7 (1961): 321-322.

[2] James Aspnes, QuickSelect.

Top K问题的两种解决思路的更多相关文章

  1. 史上最全的CSS hack方式一览 jQuery 图片轮播的代码分离 JQuery中的动画 C#中Trim()、TrimStart()、TrimEnd()的用法 marquee 标签的使用详情 js鼠标事件 js添加遮罩层 页面上通过地址栏传值时出现乱码的两种解决方法 ref和out的区别在c#中 总结

    史上最全的CSS hack方式一览 2013年09月28日 15:57:08 阅读数:175473 做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我 ...

  2. ListView+CheckBox两种解决方式及原因分析

    近期在用ListView+CheckBox搞一个item选中的项目,我将CheckBox的focus设置为false,另我大喜的是,CheckBox居然能够选中(窃喜中),这么简单就搞定了,由于数据量 ...

  3. IOS-43-导航栏标题navigationItem.title不能改变颜色的两种解决方法

    IOS-43-导航栏标题navigationItem.title不能改变颜色的两种解决方法 IOS-43-导航栏标题navigationItem.title不能改变颜色的两种解决方法 两种方法只是形式 ...

  4. [Android]Eclipse 安装 ADT[Android Development Tooling] 失败的两种解决办法

    原因 最近想在新装的 Win7 里搭建一下 Android 的开发环境,虽然现在有 Android Studio 了,不过还是习惯 Eclipse 一点.众所周知的原因,Eclipse 直接安装 AD ...

  5. win7系统不能用telnet命令的两种解决方法

    电脑专业人员对telnet命令都不陌生了,Telnet当成一种通信协议,在日常工作中,经常面对网络问题的人都会用到telnet命令,因为简单有效,可以帮助更快的找出问题.要是在使用过程中碰到win7纯 ...

  6. JavaScript监听手机物理返回键的两种解决方法

    JavaScript没有监听物理返回键的API,所以只能使用 popstate 事件监听. 有两个解决办法: 1.返回到指定的页面 pushHistory(); window.addEventList ...

  7. 64位win10系统无法安装.Net framework3.5的两种解决方法

    参考网站: https://blog.csdn.net/zang141588761/article/details/52177290 在Windows10中,当我们安装某些软件的时候会提示“你的电脑上 ...

  8. 64位win10系统无法安装.Net framework3.5的两种解决方法【转】

    近日有网友反映在windows10_64位系统电脑上安装Net framework3.5,操作时总失败,怎么办呢?小编下面就介绍win10 64位系统无法安装Net framework3.5的两种解决 ...

  9. win10应用程序添加到开机启动项的两种解决办法

    原文 win10应用程序添加到开机启动项的两种解决办法 在windows10系统中,如果想让应用程序在开机之后自动运行起来,可以怎么做呢? 方法一: 1.首先创建应用程序的快捷方式 找到自己想加入开机 ...

随机推荐

  1. 使用windows上 mxnet 预编译版本

    操作系统: 64位Windows10 mxnet的Windows预编译版本:下载地址 分为不支持GPUs和支持GPUs版并,一般选择GPUs版本. 将下载的压缩包解压,比如解压到D:\mxnet.然后 ...

  2. 64位系统访问注册表SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

    public int ChecNonkWoW64() { try { ; string subKey = @"SOFTWARE\Microsoft\Windows\CurrentVersio ...

  3. MAC使用GITHUB

    作者:珊姗是个小太阳链接:https://www.zhihu.com/question/20070065/answer/79557687来源:知乎著作权归作者所有,转载请联系作者获得授权. #什么是 ...

  4. python_eval的用法

    1. eval用法: 将字符串str当成有效的表达式来求值并返回计算结果. 2. eval的功能: math当成一个计算器很好用. 将字符串转换为list,tuple,dict. 3. 举例 # -* ...

  5. ngx_http_core_module模块提供的变量

    ngx_http_core_module模块在处理请求时,会有大量的变量,这些变量可以通过访问日志来记录下来,也可以用于其它nginx模块.在我们对请求做策略如改写等等都会使用到一些变量,顺便对ngx ...

  6. (简单) POJ 2387 Til the Cows Come Home,Dijkstra。

    Description Bessie is out in the field and wants to get back to the barn to get as much sleep as pos ...

  7. 使用Java操作文本文件的方法详解

    使用Java操作文本文件的方法详解 摘要: 最初java是不支持对文本文件的处理的,为了弥补这个缺憾而引入了Reader和Writer两个类 最初java是不支持对文本文件的处理的,为了弥补这个缺憾而 ...

  8. set multiset 集合实现众数的统计

    众数问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 所谓众数,就是对于给定的含有N个元素的多重集合,每个元素在S中出现次数最多的成为该元素的重数, 多重集合S重 ...

  9. 图片拉伸iOS

    - (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight: (NSInteger)topCa ...

  10. jQuery EasyUI学习资源汇总

    jQuery EasyUI学习资源汇总 EasyUi – 1.入门 EasyUi – 2.布局Layout + 3.登录界面 EasyUi – 4.datwagrid 学习Jquery EasyUI的 ...