找第k大数,最坏时间复杂度O(n)
(转载请注明出处,http://www.cnblogs.com/fangpei/p/3538331.html )
以前写过的一篇,搬过来。
上算法课的时候听到老师讲这个问题,觉得还是蛮有意思的。已知数组A,找出A[m]...A[p]中的第k大值。
很容易想到快排和冒泡。
第一种方法:用快排的分治方法,是先任意找数组中的一个元素a(a用数组的第一个元素比较方便),然后进行一次划分,就是将数组中所有大于a的数都移到a的一边,所有小于等于a的数都移到A的另一边。然后选择在哪边继续进行划分,最后找到第k大的值。
第二种方法:用冒泡的方法,是每个元素挨着比,第一趟找出最大的数,第二趟找出第2大的数,一直到找到第k大的数结束。
其实第一种方法的平均复杂度能到O(n),但是它的复杂度依赖于划分元素,最坏的时间复杂度是O(n^2)。
如果在第一种方法之上,加上一个筛选划分元素的过程,就能把最坏时间复杂度降到O(n)。筛选的过程就是把所有的数等分成很多小段,然后求所有小段的中间值。构成一个由所有中间值组成的段,然后再取中间值,作为划分元素。即中间值的中间值作为划分元素。取中间值可以先任选一种排序方法排序之后选择,因为每一小段的长度很短,不是影响复杂度的主要因素;取中间值的中间值,利用递归的方法调用自身即可。
这样就可以把最坏时间复杂度降到O(n)了,复杂度证明比较繁琐。
用C++实现了一下:
#include<iostream>
using namespace std; int r = ; //定义全局变量r, r个元素一段 void InSort( int A[], int m, int p ) //插入排序
{
int i;
for( i = m + ; i <= p; ++i ) {
int t;
t = A[i];
int j;
for( j = i - ; j >= m; --j ) {
if( t < A[j] )
A[j+] = A[j];
else
break;
}
A[j+] = t;
}
} void Swap( int &a, int &b ) //两数交换
{
int temp = ;
temp = a;
a = b;
b = temp;
} int Partition( int A[], int m, int p ) //一次划分函数
{
int i = m, j = p + ;
int x = A[m];
while( ) {
while( A[++i] > x );
while( A[--j] < x );
if( i >= j)
break;
Swap( A[i], A[j] );
}
A[m] = A[j];
A[j] = x;
return j;
} int Select( int A[], int m, int p, int k ) //返回一个i值,使得A[i]是A[m..p]中第k小元素
{
int n = , i = , j = ;
if( p - m + <= r ) {
InSort( A, m, p );
return m + k - ;
}
while( ) {
n = p - m + ;
for ( i = ; i <= int(n/r); ++i ) { //计算中间值
InSort( A, m + (i - ) * r, m + i * r - );
//将中间值收集到A[m..p]的前部
Swap( A[m+i-], A[m+(i-)*r+int(r/)] );
}
j = Select( A, m, m + int(n/r) -, int(int(n/r)/) + );
Swap( A[m], A[j] ); //产生划分元素
j = Partition( A, m, p );
if( j - m + == k)
return j;
else if( j - m + > k )
p = j - ;
else {
k = k - ( j - m + );
m = j + ;
}
}
} int main()
{
int A[] = { , , , , , , , , , , , , , , , , , , , , , , , };
int find_out = Select( A, , , );
int i;
for( i = ; i <= ; ++i )
cout << A[i] <<" ";
cout << endl;
cout << A[find_out] << endl;
return ;
}
另外:
1、上面说的都是在内存够用的前提下。
2、调这个程序的时候发现了一个问题:
void Swap( int &a, int &b )
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
才发现如果a和b表示同一个地址的时候,就是错的(不管是什么都变成0了)。
void Swap( int &a, int &b )
{
int temp = ;
temp = a;
a = b;
b = temp;
}
找第k大数,最坏时间复杂度O(n)的更多相关文章
- 牛客网-3 网易编程题(1拓扑&2二叉树的公共最近祖先&3快排找第K大数)
1. 小明陪小红去看钻石,他们从一堆钻石中随机抽取两颗并比较她们的重量.这些钻石的重量各不相同.在他们们比较了一段时间后,它们看中了两颗钻石g1和g2.现在请你根据之前比较的信息判断这两颗钻石的哪颗更 ...
- [剑指Offer]39-数组中出现次数超过一半的数字(快排延申,找第k大数同理)
题目链接 https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181&t ...
- 从一组数找第K大元素
最近做面试题,经常与到一个问题,如何高效的从一组数中找到第K大的元素. 其实我们最容易想到的肯定是蛮力法. 1. 我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总的时间复杂度为O(n*l ...
- 杨氏矩阵:查找x是否在矩阵中,第K大数
参考:http://xudacheng06.blog.163.com/blog/static/4894143320127891610158/ 杨氏矩阵(Young Tableau)是一个很奇妙的数据结 ...
- 第k大数问题
解法1: 我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总的时间复杂度为O(n*logn + k). 解法2: 利用选择排序或交互排序,K次选择后即可得到第k大的数.总的时间复杂度为O( ...
- 算法打基础——顺序统计(找第k小数)
这次主要是讲如何在线性时间下找n个元素的未排序序列中第k小的数.当然如果\(k=1 or k=n\),即找最大最小 数,线性时间内遍历即可完成,当拓展到一般,如中位数时,相关算法就值得研究了.这里还要 ...
- 第k大数(前k大数)
题目:设计一组N个数,确定其中第k个最大值 1,普通方法(先排序,然后遍历,得到第k大的数) 注:如果是数组,直接arr[k],我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总 ...
- POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)
题目链接: http://poj.org/problem? id=2104 解题思路: 由于查询的个数m非常大.朴素的求法无法在规定时间内求解. 因此应该选用合理的方式维护数据来做到高效地查询. 假设 ...
- BFPRT: O(n)最坏时间复杂度找第K大问题
同时找到最大值与最小值 找到n个元素中的最大/小值,比较次数为n-1, 找到n个元素中的最大值和最小值,可以Two Pass,比较次数为2n-2 也可以One Pass,比较次数至多为\(\left ...
随机推荐
- 把C#对象转换为json字符串
下面的代码写在ashx一般处理程序中 声明context.Response.ContentType = "application/json";代表服务器端返回的数据为json字符串 ...
- HTML5 文件域+FileReader 读取文件(一)
在HTML5以前,HTML的文件上传域的功能具有很大的局限性,这种局限性主要体现在如下两点: 每次只能选择一个文件进行上传 客户端代码只能获取被上传文件的文件路径,无法访问实际的文件内容 一.File ...
- SQL 查询的执行过程
所述内容均来自互联网,文章仅作为学习笔记,备忘使用. 有时候我在想我们总是在谈优化,FA 优化结构.优化框架.优化程序…,可是我真的了解将要进行的操作[优化]吗?以最近我的工作-优化SQL为例,我真的 ...
- big_table练习数据表
big_table练习数据表 create table big_table as select rownum id, a.* from all_objects a / alter table big_ ...
- shareSDK微博分享出现: 分享失败: 错误描述:Insufficient app permissions! 错误码:10014
这个错误是由于appKey所在账号没有微博高级写入接口权限, 需要申请, 详见: http://www.mamicode.com/info-detail-936938.html
- 初涉JavaScript模式 (2) : 基本技巧
尽量少用全局变量 大量使用全局变量会导致的后果 全局变量创建以后会在整个JavaScript应用和Web页面中共享.所有的全局变量都存在于一个全局命名空间内,很容易发生冲突 不知不觉创建了全局变量 其 ...
- js 求两个日期之间相差天数
//求两个日期之间的相差天数 function daysBetween(DateOne, DateTwo) { var OneMonth = DateOne.substring(5, DateOne. ...
- 安装vs2013 Sqlserver 无法连接远程服务器的解决方法
以“管理员身份”启动cmd,执行“netsh winsock reset”命令.
- java学用代码
/** *Java获取IP代码 */ import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.ev ...
- Codeforces Round #313 A Currency System in Geraldion
A Currency System in Geraldion Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64 ...