如何在O(n)内获取一个数组比如{9, 1, 2, 8, 7, 3, 6, 4, 3, 5, 0, 9, 19, 39, 25, 34, 17, 24, 23, 34, 20}里面第K大的元素呢?

我们可以使用类似快排的分区方式,将第K大的元素限定在数组的左边或右边,递归求取。

我的Java代码实现如下:

 package com.structure.sort;

 /**
* @author zhangxingrui
* @create 2019-01-27 22:52
**/
public class QuickSort { public static void main(String[] args) {
int[] numbers = {9, 1, 2, 8, 7, 3, 6, 4, 3, 5, 0, 9, 19, 39, 25, 34, 17, 24, 23, 34, 20};
// int[] numbers = {3,1,2};
// 快速排序借助递归来实现,重要的是要找到递归的终结条件(不然容易发生堆栈异常)
// 递推公式:quickSort(p...r) = merge(p, q - 1) + merge(q+1, r)
// 终结条件:p >= r
/*quickSort(numbers, 0, numbers.length - 1);
for (int number : numbers) {
System.out.println(number);
}*/ int k = getK(4, numbers, 0, numbers.length - 1);
System.out.println(k);
} private static void quickSort(int[] numbers, int p, int r){
if(p >= r)
return;
int q = partition(numbers, p, r, false);
quickSort(numbers, p, q - 1);
quickSort(numbers, q + 1, r);
} /**
* @Author: xingrui
* @Description: 分区
* @Date: 23:13 2019/1/27
*/
private static int partition(int[] numbers, int p, int r, boolean isAsc){
int k = numbers[r];
int i = p; if(isAsc){
for (int j = p; j <= r; ++j) {
if(numbers[j] < k){
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
i++;
}
}
numbers[r] = numbers[i];
numbers[i] = k;
return i;
}else{
for (int j = p; j <= r; ++j) {
if(numbers[j] > k){
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
i++;
}
}
numbers[r] = numbers[i];
numbers[i] = k;
return i;
} } /**
* @Author: xingrui
* @Description: 获取第K大的元素
* @Date: 23:15 2019/1/29
*/
private static int getK(int k, int[] numbers, int p, int r){
int q = partition(numbers, p, r, false); if(q + 1 == k)
return numbers[q]; if(q + 1 > k){
return getK(k, numbers, p, q - 1);
}else{
return getK(k, numbers, q + 1, r);
}
} }

原理就是我们先任取一个数作为分区的数,把大于它的数放在它的左边,小于它的数放在它的右边。

假设我们有数组array[p...r],那么第一次分区之后就形成了array[p...q-1],q,array[q+1...r]三个部分,如果我们要求取第3大的元素,

那么就将3与q+1做比较,

如果3==q+1,那么说明array[p...q-1]里面只有两个元素且都>array[q],而array[q+1,r]都<q,所以array[q]

就是第三大的元素;

如果3 > q+1,说明array[p...q-1]里面的元素只有一个元素,所以我们需要到array[q+1...r]里面再去找;

如果3 < q+1,则说明array[p...q-1]里面有三个元素,所以我们还需要到array[p...q-1]里面去找。

这样的话,每次只会到分区的一半的数组里面去找:n/2 + n/4 + n/8 + 直到区间缩小为1,最终可得2n - 1,

所以这样做的时间复杂的就是O(n)。

获取一个数组里面第K大的元素的更多相关文章

  1. [leetcode]215. Kth Largest Element in an Array 数组中第k大的元素

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  2. 寻找数组中的第K大的元素,多种解法以及分析

    遇到了一个很简单而有意思的问题,可以看出不同的算法策略对这个问题求解的优化过程.问题:寻找数组中的第K大的元素. 最简单的想法是直接进行排序,算法复杂度是O(N*logN).这么做很明显比较低效率,因 ...

  3. [LeetCode] Kth Largest Element in an Array 数组中第k大的数字

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  4. 寻找数组中第K大的数

    给定一个数组A,要求找到数组A中第K大的数字.对于这个问题,解决方案有不少,此处我只给出三种: 方法1: 对数组A进行排序,然后遍历一遍就可以找到第K大的数字.该方法的时间复杂度为O(N*logN) ...

  5. [经典算法题]寻找数组中第K大的数的方法总结

    [经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26   字体:[大 中 小] 打印复制链接我要评论   今天看算法分析是,看到一个这样的问题,就是在一堆数据 ...

  6. HDU 5249 离线树状数组求第k大+离散化

    KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  7. 算法题之找出数组里第K大的数

    问题:找出一个数组里面前K个最大数. 解法一(直接解法): 对数组用快速排序,然后直接挑出第k大的数.这种方法的时间复杂度是O(Nlog(N)).N为原数组长度. 这个解法含有很多冗余,因为把整个数组 ...

  8. 求一个数组的最大k个数(java)

    问题描写叙述:求一个数组的最大k个数.如,{1,5,8,9,11,2,3}的最大三个数应该是,8,9,11 问题分析: 1.解法一:最直观的做法是将数组从大到小排序,然后选出当中最大的K个数.可是这种 ...

  9. [LeetCode] 215. Kth Largest Element in an Array 数组中第k大的数字

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

随机推荐

  1. Git创建本地分支并关联远程分支

    创建本地分支git branch 分支名 例如:git branch dev,这条命令是基于当前分支创建的本地分支,假设当前分支是master(远程分支),则是基于master分支创建的本地分支dev ...

  2. HDU 1208 Pascal's Travels 经典 跳格子的方案数 (dp或者记忆化搜索)

    Pascal's Travels Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Su ...

  3. 安卓apk重新签名教程

    可能大家会有疑问,为什么安卓apk文件要重新签名,签名后有什么作用.这里我简单说一下,如果大家一直都是用官方的app的话那是不需要重新签名的.重新签名是对官方app进行了修改(如icon.图片.代码等 ...

  4. iOS:Masonry约束经验(19-03-21更)

    1.label约束: 1).只需约束x.y 点相关就行.宽高 长度相关不用约束,就算用boundingRectWithSize计算出来的,也可能不准. 如:top.bottom二选一,trailing ...

  5. 清理 Xcode 10 记录

    1,清理 ~/Library/Developer/CoreSimulator/Devices 说明:该目录存放当前的所有模拟器,每个标识符代表一台机器,清理掉避免存在旧版本的模拟器缓存 执行: 关闭模 ...

  6. Qt绘制动态曲线

    首先*.pro文件中加一句 QT += charts 然后 mainwindow.cpp文件如下: #include "mainwindow.h" #include "u ...

  7. 高性能MySQL--创建高性能的索引

    关于MySQL的优化,相信很多人都听过这一条:避免使用select *来查找字段,而是要在select后面写上具体的字段. 那么这么做的原因相信大家都应该知道:减少数据量的传输. 但我要讲的是另外一个 ...

  8. LEFT JOIN个别问题

    SELECT a.loginuser, a.schoolid, count(b.id)FROM vhs_school AS aLEFT JOIN vhs_attence AS b ON a.schoo ...

  9. HTTP1.0,HTTP1.1,HTTP2.0的主要特征对比

    HTTP1.0 是一种无状态.无连接的应用层协议. HTTP1.0规定浏览器和服务器保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务 ...

  10. Find the Duplicate Number (寻找重复数字)

    对于一个长度为n+1的数组,其中每一个值的取值范围是[1,n],可以证明的是必然存在一个重复数字(抽屉原理),假设仅存在一个重复数字,找到他. 举例:输入:[1,3,4,2,1],输出:1 自己做的时 ...