作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4046399.html

使用分治算法,首先选择随机选择轴值pivot,并使的序列中比pivot小的数在pivot左边,比pivot大的数在pivot右边,即快速排序算法中的partition的过程,可以参考:快速排序算法 Quick sort

进行partition过程后,我们随机选择的轴值为序列的第j个,且其左边有a个数,右边有b个数。

如果j=k,那么说明该轴值就是第k小个数。

如果j>k,说明第k小的数一定在轴值的左边,我们可以递归的查找左侧a个数中的第k大个数。

如果j<k,说明第k小的数一定在轴值的右侧,且其左侧的a+1个数都小于第k小的数,所以我们可以递归的查找右侧b个数中的第k-a-1小的数。

由于每次规模缩小一半,且每次处理的时间为O(n),那么我们可以得到其平均复杂度为:T(n)=T(n/2)+n

根据主定理我们可以得到算法的复杂度为O(n)

代码如下:

 #include <cstdio>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
int partation(vector<int> &vec, int begin, int end, int pivot)
{
swap(vec[pivot], vec[begin]);
int tmp = vec[begin];
int p = begin, q = end;
while( p < q )
{
while( p < q && vec[q] >= tmp) q--;
if( p < q ) vec[p++] = vec[q];
while( p < q && vec[p] < tmp ) p++;
if( p < q ) vec[q--] = vec[p];
}
vec[p] = tmp;
return p;
}
int FindKMin(vector<int> & vec, int begin, int end, int k)
{
srand(time());
int piovt = rand()%(end-begin+)+begin;
int pos = partation(vec, begin, end, piovt);
if( pos-begin+ == k )
{
return vec[pos];
}
else if( pos-begin+ > k )
{
return FindKMin(vec, begin, pos-, k);
}
else
{
return FindKMin(vec, pos+, end, k-(pos-begin+));
}
}
int main(int argc, char *argv[])
{
int n;
vector<int> vec;
while( cin >> n )
{
vec.clear();
int k;
cin>>k;
int tmp;
for( int i = ; i < n ; i++ )
{
cin>>tmp;
vec.push_back(tmp);
}
cout<<FindKMin(vec, , vec.size()-, k)<<endl;
}
}

该方法的最坏复杂度为$O(n^2)$,最坏情况是第一阶段每次选择的轴都为最大的数,并递归计算前n-1个数的第k小数,直到第k小数为这个序列的最大值为止。第二阶段每次选择的轴为最小的数,直到只剩下第k小数这一个数。那么该复杂度为$O(n^2)$。

我们可以使用另一种方法来替代随机选择轴值,并使得该算法的最坏情况的复杂度也为O(n),选择轴值方法如下:

1. 将输入数组的n个元素划分为$\lfloor n/5 \rfloor$,每组5个元素,至多只有一组由剩下的nmod5个元素组成。

2. 寻找$\lceil n/5 \rceil$个组中每组的中位数,即对其进行排序,从而找到$\lceil n/5 \rceil$个中位数,并对这$\lceil n/5 \rceil$个中位数组成的数组继续递归调用找出其轴值。

使用该方法找到的轴值并不是数组真正的中位数。但是它具有一定的性质,在大于轴值的那些中位数的组且不包括最后个数少于5的那个组中,每组至少有3个数大于轴值。不计算这两个组,大于轴值的元素个数至少为:

\begin{equation} 3(\lceil \frac{1}{2}\lceil \frac{n}{5}\rceil\rceil -2) \geq \frac{3n}{10}-6 \end{equation}

从而时间复杂度为:$T(n) \leq T(\lceil n/5 \rceil ) + T(7n/10+6) + O(n) = O(n)$

选择轴值的代码,需要建立一个类unit来保存第i个数的值和其位置,并且最终返回轴值的位置。main函数包括了数组长度为4-6的数全排列的测试。

代码如下:

 #include <cstdio>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class unit
{
public:
int x, num;
unit(int xx=, int nn=)
{
x = xx;
num = nn;
}
bool operator < (const unit &a) const
{
return this->x < a.x;
}
};
int getp(vector<unit> vec)
{
if( vec.size() <= )
{
sort(vec.begin(), vec.end());
return vec[vec.size()/].num;
}
vector<unit> small;
unit tmp;
for( int i = ; i < vec.size()-vec.size()% ; i+= )//i is the start index in the team
{
sort(vec.begin()+i, vec.begin()+i+);
// for( int j = 0 ; j < 5 ; j++ )
// {
// cout<<vec[i+j].x<<" ";
// }
// cout<<endl;
tmp.x = vec[i+].x;
tmp.num = vec[i+].num;
small.push_back(tmp);
}
int remain = vec.size()%;
int teamnum = vec.size()/;
if( remain != )
{
sort(vec.begin()+teamnum*, vec.end());
tmp.x = vec[teamnum*+remain/].x;
tmp.num = vec[teamnum*+remain/].num;
small.push_back(tmp);
}
// for( int i = 0 ; i < small.size() ; i++ )
// {
// cout<<small[i].x<<" ";
// }
// cout<<endl;
return getp(small);
}
int getpivot(const vector<int> vec)
{
vector<unit> vecunit;
unit tmp;
for( int i = ; i < vec.size() ; i++ )
{
tmp.x = vec[i];
tmp.num = i;
vecunit.push_back(tmp);
}
return getp(vecunit);
}
int main(int argc, char *argv[])
{
vector<int> a;
for( int i = ; i < ; i++ )
{
a.clear();
for( int j = ; j < i ; j++ )
{
a.push_back(j);
}
cout<<endl;
do{
cout<<"array is ";
for( int k = ; k < a.size() ; k++ )
{
cout<<a[k]<<" ";
}
cout<<endl;
cout<<"result "<<getpivot(a)<<endl;
}while(next_permutation(a.begin(), a.end()));
}
}

计算序列中第k小的数的更多相关文章

  1. 顺序统计:寻找序列中第k小的数

    最直观的解法,排序之后取下标为k的值即可. 但是此处采取的方法为类似快速排序分块的方法,利用一个支点将序列分为两个子序列(支点左边的值小于支点的值,支点右边大于等于支点的值). 如果支点下标等于k,则 ...

  2. #7 找出数组中第k小的数

    「HW面试题」 [题目] 给定一个整数数组,如何快速地求出该数组中第k小的数.假如数组为[4,0,1,0,2,3],那么第三小的元素是1 [题目分析] 这道题涉及整数列表排序问题,直接使用sort方法 ...

  3. 选择问题(选择数组中第K小的数)

    由排序问题可以引申出选择问题,选择问题就是选择并返回数组中第k小的数,如果把数组全部排好序,在返回第k小的数,也能正确返回,但是这无疑做了很多无用功,由上篇博客中提到的快速排序,稍稍修改下就可以以较小 ...

  4. Leetcode 668.乘法表中第k小的数

    乘法表中第k小的数 几乎每一个人都用 乘法表.但是你能在乘法表中快速找到第k小的数字吗? 给定高度m .宽度n 的一张 m * n的乘法表,以及正整数k,你需要返回表中第k 小的数字. 例 1: 输入 ...

  5. Java实现 LeetCode 668 乘法表中第k小的数(二分)

    668. 乘法表中第k小的数 几乎每一个人都用 乘法表.但是你能在乘法表中快速找到第k小的数字吗? 给定高度m .宽度n 的一张 m * n的乘法表,以及正整数k,你需要返回表中第k 小的数字. 例 ...

  6. ch1_5_2求无序序列中第k小的元素

    import java.util.Arrays; import java.util.PriorityQueue; public class ch1_5_2求无序序列中第k小的元素 { public s ...

  7. 每天一道算法题(32)——输出数组中第k小的数

    1.题目 快速输出第K小的数 2.思路 使用快速排序的思想,递归求解.若键值位置i与k相等,返回.若大于k,则在[start,i-1]中寻找第k大的数.若小于k.则在[i+1,end]中寻找第k+st ...

  8. [Swift]LeetCode668. 乘法表中第k小的数 | Kth Smallest Number in Multiplication Table

    Nearly every one have used the Multiplication Table. But could you find out the k-th smallest number ...

  9. 求一个数组中第K小的数

    面试南大夏令营的同学说被问到了这个问题,我的第一反应是建小顶堆,但是据他说用的是快排的方法说是O(n)的时间复杂度, 但是后来经过我的考证,这个算法在最坏的情况下是O(n^2)的,但是使用堆在一般情况 ...

随机推荐

  1. Codeforces Round #268 (Div. 1) B. Two Sets 暴力

    B. Two Sets Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/468/problem/B ...

  2. 使用Zipalign工具优化Android APK应用记录

    生成的Android应用APK文件最好进行优化,因为APK包的本质是一个zip压缩文档,经过优化能使包内未压缩的数据有序的排列,从而减少应用程序运行时的内存消耗.我们可以使用Zipalign工具进行A ...

  3. Centos部署nagios+apache实现服务器监控

    1.Nagios介绍 nagios是 一款功能强大的网络监视工具,它可以有效的监控windows.linux.unix主机状态以及路由器交换机的网络设置,打印机工作状态等,并将状态出 现异常的服务及时 ...

  4. unity3d NGUI多场景共用界面制作

    1创建单独编辑UI的unity场景 UIScene.unity 用来做UI面界 ,创建Resources文件存放UI界面的prefab,代码里动态load资源仅仅能从Resources目录载入 2创建 ...

  5. android132 360 05 手机定位

    .网络定位:根据ip地址定位,根据ip地址在实际地址数据库中查询实际地址. 缺点:动态ip导致地址不准确. .基站定位:3个基站就可以确定实际位置,定位范围是几百米到几公里不等. .GPS定位:美国卫 ...

  6. Struts2 Action的访问路径

    1.     Action的访问路径 扩展名 缺省以.action结尾,请参考:default.properties文件,可以通过配置改变这一点: <constant name="st ...

  7. C#_delegate - Pair<T> 静态绑定

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. Redis & Sentinel 安装脚本

    #!/bin/bash # 判断是否为root用户,不是root用户提示退出 if [[ $EUID -ne 0 ]]; then    echo "This script. must be ...

  9. 项目移植过程中报:“Project facet Java version 1.7 is not supported.” 错误

    转载: http://my.oschina.net/nly/blog/349081 在移植eclipse项目时,如果遇到 报:“Project facet Java version 1.7 is no ...

  10. 【转载】Hadoop和大数据:60款顶级大数据开源工具

    一.Hadoop相关工具 1. Hadoop Apache的Hadoop项目已几乎与大数据划上了等号.它不断壮大起来,已成为一个完整的生态系统,众多开源工具面向高度扩展的分布式计算. 支持的操作系统: ...