找第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 ...
随机推荐
- Cookie的读写
记住怎么写就可以了,不要问我为什么=_= 设置值的页面:context.Response.SetCookie(new HttpCookie("username",username) ...
- HTML简要内容
1. html基础 html是用来制作网页的标记语言,不需编译,直接由浏览器执行.大小写不敏感,推荐使用小写.html文件必须使用html或htm为文件名后缀. html主体结构: (1)DTD头: ...
- maven自动部署到tomcat的问题
最近需要使用Maven将项目自动部署到Tomcat,在网络上也查找了很多文章,内容大同小异,今天打算在这里给自己做一个小总结 参考网址:http://blog.csdn.net/dilaomimi/a ...
- Access数据库数据转换Table.Json
使用WPF组件 xaml <Window x:Class="JsonConvert.MainWindow" xmlns="http://schemas.micros ...
- L-value 和 R-value.
An L-value is something that can appear on the left side of an equal sign, An R-value is something t ...
- 用XMPP实现完整Android聊天项目
简介 这是一个完整的xmpp的Android的项目服务端使用openfire3.9.3客户端使用Android4.2.2 集成第三方:百度地图sdkasmack.jaruniversal-image- ...
- A simple stack
// simple stack.cpp : 定义控制台应用程序的入口点.// #include "stdafx.h"#include<iostream>using na ...
- 如何遍历json属性和动态添加属性
var person= { name: 'zhangsan', pass: '123' , 'sni.ni' : 'sss', hello:function (){ for(var i=0;i< ...
- sql -实验二
8. 统计各部门下工资大于2000的雇员的平均工资. select avg(sal)from empwhere sal>2000;
- ASP.NET WEB API 2 框架揭秘 读书笔记(一)
第一章 概述 主要内容是介绍Web的基本概念,Restfull的基本概念及特性.最后介绍创建简单WebApi程序的步骤. Web的基本概念 IP/TCP协议簇分层,分为两种 链路层->网络层-& ...