分析:此题可以用排序算法做,但考虑到最好的排序算法是快排,其时间复杂度O(NlogN)。又题目要求的是第k小的数。将整个数组排序会带来额外的时间花费。考虑用快速选择算法:
如图,对数组进行一趟快速排序后,情形如下,其中pivot是第一趟排序的主元:
此时知道,pivot左边的数全部小于等于pivot的值,右边大于等于pivot值,即pivot左边的所有数均小于等于pivot右边的的所有数。若k小于pivot左边的元素个数,则整证明第k小的数位于pivot的左边。此时只需对左边进行递归排序即可,同理可知k位于pivot右边的情况。当k位于pivot左边时,他就是左边数组中第k小的数。若其在右边,则他应该是右边数组第(k-左边元素个数)小的数。考虑时间复杂度:设有N个元素,则递归左边的期望时间复杂度是:
T(N)=O(N)+O(N/2)+O(N/4)…=O(N)显然复杂度好于快排。
核心代码:
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],n,k;
void swap(int &a,int &b){
int t=a;
a=b;
b=t;
}
int qS(int l,int r,int k){
if(l==r)
return a[l] ;
int x=a[(l+r)>>1],i=l-1,j=r+1;
while(i<j)
{
while(a[++i]<x);
while(a[--j]>x);
if(i<j)
swap(a[i],a[j]);
}
int s1=j-l+1;
if(k<=s1)
return qS(a,l,j);
return qS(a,j+1,r);
}