博客转载地址:https://blog.csdn.net/flyawayl/article/details/53538369

思路:

利用快速排序的思想,把数组递归划分成两部分。设划分为x,数组左边是小于等于x,右边大于x。

关键在于寻找一个最优的划分,经过 Blum 、 Floyd 、 Pratt 、 Rivest 、 Tarjan五位大牛的研究总结,提出了BFPRT 算法(也就是中位数的中位数算法)

解决方案

利用中位数的中位数算法得到的数作为划分可以实现最优划分–在最差情况下能实现O(n)复杂度。接下来考虑可能出现许多重复的数,假设数组中所有的数全部相同,每次划分之后都是当前区间的右端点,即会退化到O(n^2)复杂度

优化方法

一个比较好的办法就是改写partion算法,设每次划分的标准数为x,将所有的与x相等的元素集中到一起,例如数组a[]={4,4,4,2,1,4,5,6},x=4,划分之后应该是{1,2,4,4,4,4,5,6}。很容易能得到等于x的元素的个数cnt,接下来就是决策的处理:
设当前划分的下标为ind.
如果ind+1==k,直接返回a[ind]
如果ind+1<k,递归进入[ind+1,r)的区间继续寻找答案
接下来就是处理重复元素的关键步骤,如果ind+1>k
可分成两种情况:
1、k位于重复元素[ind+1-cnt+1,ind+1]之中,直接返回a[ind],直接结束程序.
2、k位于所有重复元素之前,则应该丢弃重复元素,递归进入[l,ind-cnt+1)的区间继续寻找答案

当然,这题n<=10^6,直接用sort以O(nlgn)也能过。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
int a[maxn];
int n,k;
inline int findmid(int l,int r){  //中位数的中位数 if(r-l<=5) return (l+r)/2;for(int i=0;i<(r-l)/5;++i){sort(a+l+i*5,a+l+i*5+5);swap(a[l+i],a[l+i*5+2]);}return findmid(l,l+(r-l)/5);
}
int partion(int l,int r,int &p){ //改进版partion int h=findmid(l,r);swap(a[h],a[r-1]);p=0;int ind=l-1;for(int i=l;i<r-1;++i){if(a[i]==a[r-1]) ++p;if(a[i]<=a[r-1])swap(a[++ind],a[i]);}++p;swap(a[++ind],a[r-1]);int i=l,j=ind-1;while(i<j){if(a[i]==a[ind]){while(a[j]==a[ind]) --j;if(i<j){swap(a[i],a[j]);--j;}}++i;}return ind;
}
int solve(int l,int r){int p=0;int ind=partion(l,r,p);if(ind+1==k) return a[ind];if(ind+1>k){if(ind+1-p+1<=k) return a[ind];else return solve(l,ind-p+1);} if(ind+1<k) return solve(ind+1,r);
}
int main(){scanf("%d%d",&n,&k);for(int i=0;i<n;++i) scanf("%d",&a[i]);printf("%d\n",solve(0,n));return 0;
}

求第k小的数 O(n)复杂度相关推荐

  1. 两个有序数组合起来求第k小的数+左老师专访ACM大神(笔记)8月5日斗鱼直播实录

    1.长度相等的两个有序数组寻找上中位数 注:上中位数1 2 3 4 5 6为3(偶数两个中位数为前面那个) 思路:去掉不可能为上中位数的,剩下的简化组合求上中位数. 1.1 奇数序列 位置 位置 位置 ...

  2. C++:求第k小的数

    问题:给定n(1<=n<=1000000)个元素,求第k小数(1<=k<=n). 输入:一组样例.第一行输入两个整数n和k.第二行输入n个不同的int范围内的数. 输出:输出一 ...

  3. 求第k小的数(洛谷P1923题题解,Java/C++语言描述)

    题目要求 题目链接 分析 <查找第K大/小元素算法> 这题不使用线性复杂度算法是过不去的(除非你用C++的[内置函数]or[快读+sort()]) Java应该是不可能过去的,你用C++可 ...

  4. 借组磁带机求第K小元素

    如果输入在磁带机上, 你的机器只有一个磁带机驱动器和几十字的内存,如何找第K小的数 1. 遍历一遍磁带,随即选择一个数M 2. 再遍历一遍磁带, 计算大于和小于M的个数,这样就可以获得数M在总序列中的 ...

  5. 第K小的数BFPRT算法

    介绍 BFPRT是解决求一个数组中第K小的数的算法,可以时间O(N)的时间复杂度,而使用排序求第K小的数的算法的时间复杂度为O(NlogN),因此BFPRT算法更加高效 思想 (1)分组:将原数组每五 ...

  6. python递归算法 电影院票价问题_算法课堂实验报告(二)——python递归和分治(第k小的数,大数乘法问题)...

    python实现递归和分治 一.开发环境 开发工具:jupyter notebook 并使用vscode,cmd命令行工具协助编程测试算法,并使用codeblocks辅助编写C++程序 编程语言:py ...

  7. html5数组查找第二大数,2021-06-29:在两个都有序的数组中找整体第K小的数。

    2021-06-29:在两个都有序的数组中找整体第K小的数. 福大大 答案2021-06-29: 1.A和B长度不等的时候,需要把A和B的长度变成相等. A是短数组,B是长数组. 第k小的数,k从1开 ...

  8. hdu3949(线性基,求第k小的异或和

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3949 XOR Time Limit: 2000/1000 MS (Java/Others)    Me ...

  9. 第k小的数(二分、partition)

    题目 要求以最快效率求出一个乱序数组中的第k小的数 例如:{1,6,7,2,3} 第k=3小的数为3 解法 如何找次序?利用partition分界左边是小数右边是大数,那么就能知道partition的 ...

最新文章

  1. 取得数组中的随机数random.nextInt(index)
  2. 如何根据指定软件版本制作属于自己的puppet yum源
  3. sql2005主从数据库同步配置
  4. 研究性论文的图注应该怎么写?
  5. 笔记本电脑电源已接通未充电_dell xps15 电源已接通 未充电 维修方法
  6. Maven+eclipse快速入门
  7. 提交表单上传照片预览
  8. DPDK - TX-Offload Checksum
  9. EXCEL文件转换PDF文件
  10. #Geek Talk# 董飞老师同大家一起聊聊斯坦福创业课程CS183C
  11. html5页面设计技术,H5页面设计技巧有哪些?-鱼爪网
  12. 手机总是耗电太快,怎么办?
  13. 360安全卫士造成Sharepoint文档库”使用资源管理器打开“异常
  14. 局域网服务器文件夹隐藏,共享文件设置隐藏 隐藏共享文件夹的方法
  15. 树结构(Java实现)
  16. Lucas定理——推导及证明
  17. 90% 前端都会的 ES6 简化代码技巧,你用过哪些
  18. 360下载win2003
  19. C#获取本周的周一以及周日
  20. 你会在 JitPack 上创建依赖库吗?

热门文章

  1. 北京内推 | 微软亚洲研究院机器学习组招聘AI for Science研究实习生
  2. 客户端和服务器端的用户认证
  3. 镜像、镜像文件以及挂载镜像
  4. 蓝牙运动耳机哪个好,比较好的运动蓝牙耳机
  5. oracle更新时间分钟,oracle 时间字段自动更新问题
  6. 玩转群晖NAS套件系列六:Web Station的安装与使用保姆级教程!
  7. 二维码登录(二)生成二维码
  8. 信息化与信息系统(1)
  9. mysql数据库物理结构设计_MySQL之数据库结构设计
  10. 【转】宋代的“福利国家”气象