在一个无序序列中找出第k个元素,对于k很小或者很大时可以采取特殊的方法,比如用堆排序来实现 。但是对于与序列长度N成正比的k来说,就不是一件容易的事了,可能最容易想到的就是先将无序序列排序再遍历即可找出第k个元素。由于任何基于比较的排序算法不可能用少于Θ(N lgN)次比较来实现将所有元素排序,所以采用排序的方法的时间复杂度是线性对数级别的。

我们可以借鉴快速排序中将序列划分的思想来实现平均情况下线性级别的算法,算法实现如下:

  1. public class KthElement {
  2.  
  3. private static void exch(Comparable[] a, int i, int j)
  4. {
  5. Comparable swap = a[i];
  6. a[i] = a[j];
  7. a[j] = swap;
  8. }
  9.  
  10. private static boolean less(Comparable a, Comparable b)
  11. {
  12. return a.compareTo(b) < 0;
  13. }
  14.  
  15. private static int partition(Comparable[] a, int lo, int hi)
  16. {
  17. int i = lo;
  18. int j = hi + 1;
  19. Comparable v = a[lo];
  20. while(true)
  21. {
  22. while(less(a[++i], v)) if(i == hi) break;
  23. while(less(v, a[--j]));
  24. if(i >= j) break;
  25. exch(a, i, j);
  26. }
  27. exch(a, lo, j);
  28. return j;
  29. }
  30.  
  31. public static Comparable select(Comparable[] a, int k)
  32. {
  33. int lo = 0;
  34. int hi = a.length - 1;
  35. while(hi > lo)
  36. {
  37. int j = partition(a, lo, hi);
  38. if(j == k) break;
  39. else if(j > k) hi = j - 1;
  40. else if(j < k) lo = j + 1;
  41. }
  42. return a[k];
  43. }
  44. public static void main(String[] args) {
  45. Integer[] ints = {5, 3, 1, 4, 2};
  46. int find = (int) select(ints, 2);
  47. System.out.println(find);
  48. }
  49.  
  50. }

在select方法中,使用partition方法将序列划分。如果k = j,问题就已经解决了; 如果k < j,就继续切分左字数组(令 hi = j - 1);如果k > j,就继续切分右子数组(令lo = j + 1)。该循环保证了lo左边的元素都小于等于a[lo...hi], 而hi右边的元素都大于等于a[lo...hi],我们不断切分直到数组中只剩下第k个元素。为何这个的时间复杂度是线性级别的,证明很复杂,在此给出理想情况下的简易证明。假设每次切分都从中间切分,则所有的比较次数为(N + N/2 + N/4 + N/8 +...)直到找到k,很显然这个和小于2N。平均情况下的复杂度为Θ( 2N + 2Kln(N/K) + 2(N - K)ln(N/(N-K)) )。当K = N/2时,复杂度为Θ((2 + 2ln2)N)。

在线性级别时间内找出无序序列中的第k个元素的更多相关文章

  1. [PY3]——找出一个序列中出现次数最多的元素/collections.Counter 类的用法

    问题 怎样找出一个序列中出现次数最多的元素呢? 解决方案 collections.Counter 类就是专门为这类问题而设计的, 它甚至有一个有用的 most_common() 方法直接给了你答案 c ...

  2. 如何寻找无序数组中的第K大元素?

    如何寻找无序数组中的第K大元素? 有这样一个算法题:有一个无序数组,要求找出数组中的第K大元素.比如给定的无序数组如下所示: 如果k=6,也就是要寻找第6大的元素,很显然,数组中第一大元素是24,第二 ...

  3. 寻找无序数组中的前k大元素

    题目描述 以尽可能小的代价返回某无序系列中的两个最大值,当有重复的时设置某种机制进行选择. 题解 首先要考虑的是重复的数的问题. A.不处理重复数据方法:在处理第k大的元素时不处理重复的数据,也就是将 ...

  4. 找出N个数中最小的k个数问题(复杂度O(N*logk))

    这是一个经典的算法题,下面给出的算法都在给定的数组基础上进行,好处时不用分配新的空间,坏处是会破坏原有的数组,可以自己分配新的空间以避免对原有数组的破坏. 思路一 先直接排序,再取排序后数据的前k个数 ...

  5. 【python cookbook】【数据结构与算法】12.找出序列中出现次数最多的元素

    问题:找出一个元素序列中出现次数最多的元素是什么 解决方案:collections模块中的Counter类正是为此类问题所设计的.它的一个非常方便的most_common()方法直接告诉你答案. # ...

  6. 【python cookbook】找出序列中出现次数最多的元素

    问题 <Python Cookbook>中有这么一个问题,给定一个序列,找出该序列出现次数最多的元素.例如: words = [ 'look', 'into', 'my', 'eyes', ...

  7. Entity Framework 6 Recipes 2nd Edition(9-3)译->找出Web API中发生了什么变化

    9-3. 找出Web API中发生了什么变化 问题 想通过基于REST的Web API服务对数据库进行插入,删除和修改对象图,而不必为每个实体类编写单独的更新方法. 此外, 用EF6的Code Fri ...

  8. Python算法每日一题--001--给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗? 示例 1: 输入: [ ...

  9. 一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵

    题目描述: 一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵(矩阵中元素个数为矩阵面积) 输入: 每个案例第一行三个正整数N,M<=100,表示矩阵大小,和一个整数K 接下 ...

随机推荐

  1. 好看的游戏soul calibur

    http://soulcalibur.fr/index.php?wiki/sophitia/ http://astuce-soluce.playfrance.com/index.php/Soul_Ca ...

  2. 单独下载的Qt library则一般不带SSL(包括QT FAQ)

    http://www.cnblogs.com/E7868A/archive/2012/11/15/2771501.html http://www.oldcai.com/archives/208 htt ...

  3. linux查看某个端口是否被占用

    一个还算可以的:[root@benet ~]# netstat -nlptu |awk '{print $4,$7}' | grep 80:::80 2508/httpd这样更直观的显示出要查询的端口 ...

  4. 【.Net免费公开课】--授技.Net中的高帅富技术-"工作流"

    课程简介 免费公开课主题: .Net中的高帅富技术-“工作流” 公开课开课时间:     10月17日 19:30--21:30 公开课YY频道:       85155393   (重要:公开课QQ ...

  5. 【HDOJ】4373 Mysterious For

    1. 题目描述有两种不同类型的循环,并给出一个由1.2组成的序列,表示嵌套的循环类型.问这样组着的循环一共需要多少次循环?并将结果模364875103. 2.基本思路显然,每当遇到一个类型1的序列,即 ...

  6. Datalist增删改查——联系人管理

    关于Datalist,其实和Repeater差不多,都是存放数据的控件,相比较下,Datalist和Repeater虽然都是用的模板,但是Datalist比之多了Edit模板,也就是编辑栏的模板,事件 ...

  7. mssql查找备注(text,ntext)类型字段为空的方法

    在sql语句中,如果查找某个文本字段值为空的,可以用select * from 表 where 字段='' ,但是如果这个字段数据类型是text或者ntext,那上面的sql语句就要出错了. 解决办法 ...

  8. JS 获取Button控件的提交类型

    <script type="text/javascript"> <!--获取button控件的类型---> function isAuditOrCancel ...

  9. JDK版本1.6和6.0到底指什么

    Both version numbers (1.6.0 and 6) are used to identify this release of the Java Platform. Version 6 ...

  10. C#百万数据查询超时问题

    用c#从百万数据中筛选一些信息时,经常会出现程序连接超时的错误,常见的错误很多,例如:Timeout expired. The timeout period elapsed prior to comp ...