获取一个数组里面第K大的元素
如何在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大的元素的更多相关文章
- [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 ...
- 寻找数组中的第K大的元素,多种解法以及分析
遇到了一个很简单而有意思的问题,可以看出不同的算法策略对这个问题求解的优化过程.问题:寻找数组中的第K大的元素. 最简单的想法是直接进行排序,算法复杂度是O(N*logN).这么做很明显比较低效率,因 ...
- [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 ...
- 寻找数组中第K大的数
给定一个数组A,要求找到数组A中第K大的数字.对于这个问题,解决方案有不少,此处我只给出三种: 方法1: 对数组A进行排序,然后遍历一遍就可以找到第K大的数字.该方法的时间复杂度为O(N*logN) ...
- [经典算法题]寻找数组中第K大的数的方法总结
[经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26 字体:[大 中 小] 打印复制链接我要评论 今天看算法分析是,看到一个这样的问题,就是在一堆数据 ...
- HDU 5249 离线树状数组求第k大+离散化
KPI Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- 算法题之找出数组里第K大的数
问题:找出一个数组里面前K个最大数. 解法一(直接解法): 对数组用快速排序,然后直接挑出第k大的数.这种方法的时间复杂度是O(Nlog(N)).N为原数组长度. 这个解法含有很多冗余,因为把整个数组 ...
- 求一个数组的最大k个数(java)
问题描写叙述:求一个数组的最大k个数.如,{1,5,8,9,11,2,3}的最大三个数应该是,8,9,11 问题分析: 1.解法一:最直观的做法是将数组从大到小排序,然后选出当中最大的K个数.可是这种 ...
- [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 ...
随机推荐
- Git创建本地分支并关联远程分支
创建本地分支git branch 分支名 例如:git branch dev,这条命令是基于当前分支创建的本地分支,假设当前分支是master(远程分支),则是基于master分支创建的本地分支dev ...
- HDU 1208 Pascal's Travels 经典 跳格子的方案数 (dp或者记忆化搜索)
Pascal's Travels Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Su ...
- 安卓apk重新签名教程
可能大家会有疑问,为什么安卓apk文件要重新签名,签名后有什么作用.这里我简单说一下,如果大家一直都是用官方的app的话那是不需要重新签名的.重新签名是对官方app进行了修改(如icon.图片.代码等 ...
- iOS:Masonry约束经验(19-03-21更)
1.label约束: 1).只需约束x.y 点相关就行.宽高 长度相关不用约束,就算用boundingRectWithSize计算出来的,也可能不准. 如:top.bottom二选一,trailing ...
- 清理 Xcode 10 记录
1,清理 ~/Library/Developer/CoreSimulator/Devices 说明:该目录存放当前的所有模拟器,每个标识符代表一台机器,清理掉避免存在旧版本的模拟器缓存 执行: 关闭模 ...
- Qt绘制动态曲线
首先*.pro文件中加一句 QT += charts 然后 mainwindow.cpp文件如下: #include "mainwindow.h" #include "u ...
- 高性能MySQL--创建高性能的索引
关于MySQL的优化,相信很多人都听过这一条:避免使用select *来查找字段,而是要在select后面写上具体的字段. 那么这么做的原因相信大家都应该知道:减少数据量的传输. 但我要讲的是另外一个 ...
- LEFT JOIN个别问题
SELECT a.loginuser, a.schoolid, count(b.id)FROM vhs_school AS aLEFT JOIN vhs_attence AS b ON a.schoo ...
- HTTP1.0,HTTP1.1,HTTP2.0的主要特征对比
HTTP1.0 是一种无状态.无连接的应用层协议. HTTP1.0规定浏览器和服务器保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务 ...
- Find the Duplicate Number (寻找重复数字)
对于一个长度为n+1的数组,其中每一个值的取值范围是[1,n],可以证明的是必然存在一个重复数字(抽屉原理),假设仅存在一个重复数字,找到他. 举例:输入:[1,3,4,2,1],输出:1 自己做的时 ...