P1293 求第k小的数
\(Description\)
输入\(n\)个数字及\(k\),求第\(k\)(\(k\)从0编号)小的数
(\(n<=5e6,ai<=10^9\))
\(Solution1\)
这道题数据范围显然不能用一般排序硬做,再\(O(1)\)查询
考虑快速排序,每次确定基准值归位后对左右继续递归,此时基准值是在他应该的位置上的(也就是说基准值是第\(p\)小,那他排完序一定在\(a[p]\))
而对于这道题,我们并不需要考虑把所有数排序,比如基准值是第\(i\)大,那么若\(k<i\),只需要对\((l,i-1)\)递归,若\(k>i\),只需要对\((i+1,r)\)递归,直到\((i==k)\)
,显然平均复杂度为\(O(n)\)
\(Code 1\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#define re register
#define maxn 5000010
#define ll long long
using namespace std;
int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,a[maxn],k;
void quicksort(int l,int r)
{
if(l>=r) return;
int i=l,j=r,base=a[l];
while(i<j)
{
while(a[j]>=base&&i<j) j--;
while(a[i]<=base&&i<j) i++;
swap(a[i],a[j]);
}
swap(a[l],a[i]);
if(i==k) return;
if(i>k) quicksort(l,i-1);
else quicksort(i+1,r);
}
int main()
{
n=read(),k=read();
k++;
for(re int i=1;i<=n;++i) a[i]=read();
quicksort(1,n);
printf("%d",a[k]);
return 0;
}
\(Solution2\)
可以借助\(STL\)函数\(nth_element\),声明在\(algorithm\)库
用法如下
\(nth_element(a+x,a+x+y,a+x+len);\)
表示对\(a[x]\)到\(a[x+len-1]\)操作,保证\(a[x]~a[x+y-1]\)的数全部小于\(a[x+y]\),\(a[x+y+1]~a[x+len-1]\)的数全部大于\(a[x+y]\),但不保证顺序
也就是说,保证了\(a[x+y]\)存放的是\(a[x]~a[x+len-1]\)中第\(y+1\)小的数
此题写\(nth_element(a,a+k,a+n)\)即可