Top k问题(线性时间选择算法)
问题描述:给定n个整数,求其中第k小的数。
分析:显然,对所有的数据进行排序,即很容易找到第k小的数。但是排序的时间复杂度较高,很难达到线性时间,哈希排序可以实现,但是需要另外的辅助空间。
这里我提供了一种方法,可以在O(n)线性时间内解决Top k问题。关于时间复杂度的证明,不再解释,读者可以查阅相关资料。具体的算法描述如下:
算法:LinearSelect(S,k)
输入:数组S[1:n]和正整数k,其中1<=k<=n;
输出:S中第k小的元素
1. If n<20 Then 将S中的元素排序后输出第k个元素,算法结束;
2.将S划分为无公共元素的 floor(n/5) 个分组,每组5个元素,第 i 个组记为Si;
3.用插入排序算法将每个组Si 排序,求得中位数 mi ,其中 i=1,2,3,...,floor(n/5);
4.递归调用本算法求得{mi | 1<=i floor(n/5)}的中位数(即第floor(n/10)小的元素)M;
5.划分S为A={x|x属于S 并且 x<M}, B={x|x属于S 并且 x=M}和C={x|x属于S 并且 x>M};
6. If |A|>k Then 输出 LinearSelect(A,k);
7. ElseIf |A|+|B|<k Then 输出 LinearSelect(C,k-|A|-|B|);
8. Else 输出M,算法结束;
当然了,本题是求第k小,如果求第k大,可以转换成对应的第n-k小,同样可以求。这个算法以后会经常用到,一定要掌握,但是如果数据量不超过20个的话,也可以直接排序求。
完整的Java代码如下,代码写法都比较通用,读者可以很容易转换为其他语言实现:
import java.lang.Math;
import java.util.Arrays;
import java.util.Scanner;
public class Topk {
public static int LinearSelect(int s[],int n,int k)
{ int topk=0;
if(n<=0)return topk; //如果数组为空,则返回0
if(n<5) //这里对应算法的第一步。这里我定义的是小于5个,则直接排序,读者也可以自己设定
{
for(int i=0;i<n-1;i++)
for(int j=i+1;j<n;j++)
if(s[i]>s[j])
{int t=s[i];s[i]=s[j];s[j]=t;}
topk= s[k-1];
}
else{ int ss[][]=new int[n/5][5]; //对应算法的第二步
int j=-1;
for(int i=0;i<n/5*5;i++)
{ if(i%5==0)j++;
ss[j][i%5]=s[i]; } int sss[]=new int[n/5];
for(int i=0;i<n/5;i++) //对应算法的第三步
{
Arrays.sort(ss[i]);
sss[i]=ss[i][2]; }
Arrays.sort(sss);
int M=sss[n/5/2]; //对应算法的第四步 int A[]=new int[n]; //对应算法的第五步
int B[]=new int[n];
int C[]=new int[n];
int a=0,b=0,c=0; //作为三个结合的指针
for(int i=0;i<n;i++) //放入对应的集合中
{
if(s[i]<M)A[a++]=s[i];
if(s[i]==M)B[b++]=s[i];
if(s[i]>M)C[c++]=s[i];
} if(a>k-1)topk=LinearSelect(A,a,k); //对应算法第六步,我定义的数组是从下标0开始的忙,所以这里是k-1
else if(a+b<k-1)topk=LinearSelect(C,c,k-a-b); //对应算法第七步
else topk=M; //对应算法第八步 }
return topk; //返回最终的Top k
}
public static void main(String[] args) { int s[]={16,9,92,40,25,27};
int n=6;
int k=2;
System.out.print("数组为:");
for(int i=0;i<n;i++)
{
System.out.print(s[i]+",");
}
System.out.println();
System.out.println("第"+k+"小的数为:"+LinearSelect(s,n,k)); } }
输出结果为:
数组为:16,9,92,40,25,27,
第2小的数为:16
Top k问题(线性时间选择算法)的更多相关文章
- 【Unsolved】线性时间选择算法的复杂度证明
线性时间选择算法中,最坏情况仍然可以保持O(n). 原因是通过对中位数的中位数的寻找,保证每次分组后,任意一组包含元素的数量不会大于某个值. 普通的Partition最坏情况下,每次只能排除一个元素, ...
- Top K问题的两种解决思路
Top K问题在数据分析中非常普遍的一个问题(在面试中也经常被问到),比如: 从20亿个数字的文本中,找出最大的前100个. 解决Top K问题有两种思路, 最直观:小顶堆(大顶堆 -> 最小1 ...
- 程序员编程艺术:第三章续、Top K算法问题的实现
程序员编程艺术:第三章续.Top K算法问题的实现 作者:July,zhouzhenren,yansha. 致谢:微软100题实现组,狂想曲创作组. 时间:2011年05月08日 ...
- Top K算法
应用场景: 搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节. 假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果 ...
- [图解算法]线性时间选择Linear Select——<递归与分治策略>
#include <ctime> #include <iostream> using namespace std; template <class Type> vo ...
- 算法:线性时间选择(C/C++)
Description 给定线性序集中n个元素和一个整数k,n<=2000000,1<=k<=n,要求找出这n个元素中第k小的数. Input 第一行有两个正整数n,k. 接下来是n ...
- 排序算法Java版,以及各自的复杂度,以及由堆排序产生的top K问题
常用的排序算法包括: 冒泡排序:每次在无序队列里将相邻两个数依次进行比较,将小数调换到前面, 逐次比较,直至将最大的数移到最后.最将剩下的N-1个数继续比较,将次大数移至倒数第二.依此规律,直至比较结 ...
- 快速排序以及第k小元素的线性选择算法
简要介绍下快速排序的思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此 ...
- Top K问题-BFPRT算法、Parition算法
BFPRT算法原理 在BFPTR算法中,仅仅是改变了快速排序Partion中的pivot值的选取,在快速排序中,我们始终选择第一个元素或者最后一个元素作为pivot,而在BFPTR算法中,每次选择五分 ...
随机推荐
- Android.mk文件语法规范及使用模板
Android.mk文件语法详述 介绍:------------这篇文档是用来描述你的C或C++源文件中Android.mk编译文件的语法的,为了理解她们我们需要您先看完docs/OVERVIEW.h ...
- 在浏览器中输入Google.com并且按下回车之后发生了什么?
作者: skyline75489 来源: skyline75489的博客 发布时间: 2015-03-26 16:57 阅读: 4163 次 推荐: 23 原文链接 [收藏] ...
- 《你必须知道的495个C语言问题》知识笔记及补充
1. extern在函数声明中是什么意思? 它能够用作一种格式上的提示表明函数的定义可能在还有一个源文件里.但在 extern int f(); 和 int f(); 之间并没有实质的差别. 补充:e ...
- Android应用程序组件Content Provider简要介绍和学习计划
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6946067 在Android系统中,Conte ...
- UBUNTU系统常用基本命令
1.系统基本信息查询查看内核#uname -a 查看Ubuntu版本#cat /etc/issue 查看内核加载的模块#lsmod 查看PCI设备#lspci 查看USB设备#lsusb 查看网卡状态 ...
- VLC各个Module模块之间共享变量的实现方法
在做VLC开发的时候,想使用一个模块访问另外一个模块的数据, 比如在网络模块得到了一些数据,想在其他模块得到这些数据进行处理,这时候就需要两个模块共享一些变量. 查看VLC的源码,发现VLC专门有va ...
- Model注解的后台原理
Asp.net MVC的验证特性是由模型绑定器.模型元数据.模型验证器和模型状态组成的协调系统的一部分. 1.验证和模型绑定 默认情况下,Asp.net MVC框架在模型绑定石执行验证逻辑,在操作方法 ...
- C# HTML转换为WORD
使用aspose.words仅需要4句代码,即可搞定. Document doc = new Document(); DocumentBuilder builder = new DocumentBui ...
- JAVA byte有无符号数的转换
如果你只需要对英文文本的每个字节进行数据处理,则无需考虑有符号数和无符号数的转换问题: 但如果你需要对含有中文的文本进行字节处理,则可能需要考虑有无符号数的转换问题. 以下代码均为Java代码. 1. ...
- 浅谈UE4引擎
首先要说的是,游戏开发是一项高度复杂的代码开发工作,编程语言只是最基本的知识,它涉及的内容还有计算机图形学.3D数学.物理学等复杂的学科.但是若需要学完这么多知识才能开发游戏,恐怕许多人都已经断气了, ...