题目链接:http://acdream.info/problem?pid=1099
瑶瑶的第K大
Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 512000/256000 KB (Java/Others)
Problem Description
一天,萌萌的妹子--瑶瑶(tsyao)很无聊,就来找你玩。可是你们都不知道玩什么。。。尴尬了一阵子,机智的瑶瑶就提议:“这样吧,你说N个整数xi,然后在随意说一个数字k,我能够快速地说出这些数字里面第 k 大的数字。”
Input
第1行 两个整数N, K以空格隔开;
第2行 有N个整数(可出现相同数字,均为随机生成),同样以空格隔开。
0 < n ≤ 5*10^6 , 0 < k ≤ n
1 ≤ xi ≤ 10^8
Output
输出第
k 大的数字。
Sample Input
5 2 5 4 1 3 1
Sample Output
4
Hint
如2,2,1中三个数字中第一大数字为2,第二大数字也为2,第三大数字为1 。
利用快排思想
一个简单的寻找第k大的算法,再加上一个十(sang)分(xin)炫(bing)酷(kuang)的读入优化,就解决了..
无读入优化版
/*
* this code is made by f_xuan
* Problem: 1099
* Verdict: Accepted
* Submission Date: 2014-06-19 16:02:49
* Time: 4964 MS
* Memory: 21208 KB
*/
#include<cstdio>
#include<stdlib.h>
#include <iostream>
using namespace std;
#define N 5000010
int a[N];
int partition(int l,int r)
{
swap(a[(l+r)>>1],a[r]);//取中间值下标的值为分界线
int x = a[r];
int i = l - 1;//i用来记录比x小的数下标
for(int j = l ; j < r ; j ++)
{
if(a[j] < x)//比x小的数放到左边
{
i ++;
swap(a[i],a[j]);//交换
}
}
swap(a[i+1],a[r]);//由于从l到i都是比x小的数,那么下标i+1就应该是分界的x即a[r]
return i + 1;
}
int select(int k,int l,int r)//找出数组中第K大元素
{
while(l!=r){
int q = partition(l,r);
int t = r - q + 1;//右边数的个数
if(k == t) return a[q];//k==t那么a[q]就是答案
else if(k > t) {
k=k-t,r=q-1;//在左边进行查找,注意这里就需要查找第k-t大数了
}
else {
l=q+1;//在右边进行查找
}
}
if(l == r) return a[l];//数组中只有一个数
}
int main(void)
{
int n,k;
cin>>n>>k;
int i;
for(i=0;i<n;++i){
scanf("%d",&a[i]);
}
int r = select( k, 0, n-1);
cout<<r<<endl;
return 0;
}
标程
/*
* this code is made by tsyao
* Problem: 1099
* Verdict: Accepted
* Submission Date: 2014-06-19 16:04:32
* Time: 3852 MS
* Memory: 40148 KB
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std ;
const int maxn = 10000000 ;
int n , k , op ;
int a[maxn] ;
int read() {
int tmp = 0 ;
char x ;
while(1) {
x = getchar() ;
if(x >= '0' && x <= '9') tmp = tmp*10 + x - '0' ;
else break ;
}
return tmp ;
}
int find(int L,int R,int kth) {
if(L == R-1) return a[L] ;
int mid_num = a[(L+R)>>1];
int l = L , r = R ;
while(l < r-1) {
while(l < r && a[l] > mid_num) l++ ;
while(l < r && a[r-1] < mid_num) r-- ;
if(l < r-1) swap(a[l] , a[r-1]) ;
if(l < r-1) {l++ ; r-- ;}
}
if(r-l) {
if(a[l] > mid_num) l++ ;
else r-- ;
}
if(r-L >= kth) return find(L , r , kth) ;
else return find(r , R , kth-(r-L)) ;
}
int main() {
scanf("%d%d\n",&n,&k) ;
for(int i = 0 ; i < n ; i++) a[i] = read() ;
int tmp = find(0 , n , k) ;
printf("%d\n",tmp) ;
return 0 ;
}