要在一个序列里找出第K小元素,可以用排序算法,然后再找。可以证明,排序算法的上界为O(nlogn)。

在这里,给出两种可以在线性时间内找出第K小元素的方法。

方法1:

(1) 选定一个比较小的阈值(如44),当序列元素小于阈值时,直接用排序算法来做;

(2) 当序列元素大于阈值时,把元素划分为以5个元素为一组,每一组元素自身作排序,然后挑出每一组元素的中间值,再在所有的中间值中,递归调用本算法,挑出中间值,可以认为,此值大约为整个序列的中间值(当序列元素个数不是5的倍数时,最后一组不足5的舍掉,这个对中间值影响不大);

(图片参考《ALGORITHMS DESIGN TECHNIQUES AND ANALYSIS》 M. H. Alsuwaiyel)

(3) 把元素按中间值划分为三组,第一组小于中间值,第二组等于中间值,第三组大于中间值;

(4) 若第一组的元素个数大于等于K,即第K个元素在第一组内;若第一组和第二组的元素个数大于等于K,即中间值为第K个元素;否则,第K个元素在第三组,再递归调用本算法,注意K要减去一二组的元素个数。

    public static int select(int[] A, int k){
return selectDo(A, 0, A.length-1, k);
} private static int selectDo(int[] A, int low, int high, int k){
//select k min number
int p = high - low + 1;
if(p < 44){
Arrays.sort(A, low, high+1);
return A[low+k];
}
//A divided into q groups, each group 5 elements, and sort them
int q = p/5;
int[] M = new int[q];
for(int i = 0; i < q; i ++){
Arrays.sort(A, low + 5*i, low + 5*i + 5);
M[i] = A[low+5*i+2];
}
//select mid in M
int mid = selectDo(A, 0, q-1, (q-1)/2);
//A divided into 3 groups
int[] A1 = new int[p];
int[] A2 = new int[p];
int[] A3 = new int[p];
int count1, count2, count3;
count1 = count2 = count3 = 0;
for(int i = low; i <= high; i ++){
if(A[i] < mid)
A1[count1++] = A[i];
else if(A[i] == mid)
A2[count2++] = A[i];
else
A3[count3++] = A[i];
}
if(count1 >= k)
return selectDo(A1, 0, count1-1, k);
if(count1 + count2 >= k)
return mid;
return selectDo(A3, 0, count3-1, k-count1-count2);
}

Java

这个方法虽然可以以最坏时间复杂度O(n),但是系数值会比较大,而且算法比较复杂。

方法2:

(1) 随机挑选一个元素X作为数组的划分,此时数组分为三部分,第一部分是小于X的元素,第二部分只有一个元素就是X,第三部分是大于或等于X的元素;

(2) 当第一部分的元素个数N大于K时,说明第K个元素在第一部分;当第一部分的元素个数N等于K时,说明X就是第K个元素(注意到下标从0开始);否则,第K个元素在第三部分,再递归调用本算法,注意K要减去第一部分的元素个数再减1(包括X)。

    public static int randomSelect(int[] A, int k){
return randomSelectDo(A, 0, A.length-1, k);
} private static int randomSelectDo(int[] A, int low, int high, int k){
int i = randomPartition(A, low, high);
//n is the number of < A[i]
int n = i-low;
if(n > k)
return randomSelectDo(A, low, i-1, k);
else if(n == k)
return A[i];
else
return randomSelectDo(A, i+1, high, k-n-1);
} private static void swap(int[] A, int i, int j){
int temp = A[i];
A[i] = A[j];
A[j] = temp;
} private static int randomPartition(int[] A, int low, int high){
//random divide
Random rand = new Random();
int r = rand.nextInt(high-low+1) + low;
swap(A, low, r);
int i = low;
int x = A[low];
for(int j = low+1; j <= high; j ++){
if(A[j] < x){
i ++;
if(i != j){
swap(A, i, j);
}
}
}
swap(A, low, i);
return i;
}

Java

此方法和快速排序有点相似,也是需要划分数组的方法;与方法1相比,不同之处在于划分元素的选择。采用随机化划分,在实际上可以达到O(n)的要求。而且算法简洁优美。

寻找第K小元素的更多相关文章

  1. 减治算法之寻找第K小元素问题

    一.问题描写叙述 给定一个整数数列,寻找其按递增排序后的第k个位置上的元素. 二.问题分析 借助类似快排思想实现pation函数.再利用递归思想寻找k位置. 三.算法代码 public static ...

  2. 查询无序列表中第K小元素

    当需要在无需列表中寻找第k小的元素时,一个显然的方法是将所有数据进行排序,然后检索k个元素.这种方法的运行时间为O(n log(n)). 无序列表调用分区函数将自身分解成两个子表,其长度为i和n-i. ...

  3. Ex 2_22 两个有序列表合并后的第k小元素..._第四次作业

    package org.xiu68.ch02; public class Ex2_22 { public static void main(String[] args) { // TODO Auto- ...

  4. 中位数与第K小元素

    算法实际上是模仿快速排序算法设计出来的,其基本思想也是对输入数组进行递归划分,与快速排序不同的是,它只对划分出来的子数组之一进行递归处理: int randompartition(int a[],in ...

  5. 清橙OJ 1082 查找第K小元素 -- 快速排序

    题目地址:http://oj.tsinsen.com/A1082 问题描述 给定一个大小为n的数组s和一个整数K,请找出数组中的第K小元素. 这是一个补充程序的试题,你需要完成一个函数: int fi ...

  6. 快速排序以及第k小元素的线性选择算法

    简要介绍下快速排序的思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此 ...

  7. 算法导论学习之线性时间求第k小元素+堆思想求前k大元素

    对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思 ...

  8. (寻找第K小的数&amp;&amp;寻找第K小的数的和)

    这一篇博客以一些OJ上的题目为载体,讲一下寻找第K小的数的方法 方法一: 先将数据排列好,然后,然后return a[k]或者将前K个数加起来 方法二: 基于高速排序.如,一次高速排序将某一个数放到了 ...

  9. Coursera Algorithms week3 快速排序 练习测验: Selection in two sorted arrays(从两个有序数组中寻找第K大元素)

    题目原文 Selection in two sorted arrays. Given two sorted arrays a[] and b[], of sizes n1 and n2, respec ...

随机推荐

  1. 安装apache重启的时候,报错端口被占用,错误1

    在cmd中执行以下命令来重新分配. netsh winsock reset. 还不行的话可以重启电脑,再不行就算apache配置文件错误.

  2. Two-Phase-Commit for Distributed In-Memory Caches--reference

    Part I reference from:http://gridgain.blogspot.kr/2014/09/two-phase-commit-for-distributed-in.html 2 ...

  3. Java基础知识强化29:String类之String类构造方法

    1. 常用String构造方法使用: package cn.itcast_01; /* * 字符串:就是由多个字符组成的一串数据.也可以看成是一个字符数组. * 通过查看API,我们可以知道 * A: ...

  4. SOA

    面向服务架构Service-Oriented Architecture 4个特性 1每个服务具有明确的边界 2服务是独立的 3采用标准的契约定义和通信协议 4服务是自解释的

  5. 杂记之web篇

    问题1:通过POST方式提交给后台的数据出现了乱码,用部分浏览器测试却是好的. 解决办法: 在web.config文件中加上 <globalization responseEncoding=&q ...

  6. 【转】深入理解Java内存模型(五)——锁

    锁的释放-获取建立的happens before 关系 锁是java并发编程中最重要的同步机制.锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息. 下面是锁释放-获取的示例代 ...

  7. ibatis.net调用oracle存储过返回游标SYS_REFCURSOR结果集

    最近在用ibatis.net框架和oracle 11g开发一套程序.其中有一个需求就是通过存储过程,查询指定条件的数据集. 但是在开发的过程中遇到了问题,问题如下: 1.如何通过ibatis.net执 ...

  8. 【转】setStyleSheet用法

    [转自]http://blog.csdn.net/seanyxie/article/details/5925723 使用setStyleSheet来设置图形界面的外观: QT Style Sheets ...

  9. 你好,C++(13)这道单选题的答案是A、B、C还是D?3.7 枚举类型

    3.7  枚举类型 除了之前我们介绍的数值数据和文字数据之外,在现实世界中,常常还会遇到这样一类数据:一道单选题的答案只能是A.B.C.D四个选项中的某一个:红绿灯的颜色只能是红色,绿色和黄色中的某一 ...

  10. jsp页面间的传值

    很多的时候我们只是把我们需要的数据,查询出来,然后用request.setAttribute("" ,"" )方法保存这个数据集合.再在我们能跳转到的下一个js ...