【O(n)求第K大】ACdream 1099 瑶瑶的第K大

题目链接: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,我能够快速地说出这些数字里面第 大的数字。”

Input

第1行 两个整数N, K以空格隔开;

第2行 有N个整数(可出现相同数字,均为随机生成),同样以空格隔开。

0 < n ≤ 5*10^6 , 0 < k ≤ n

1 ≤ xi ≤ 10^8

Output
输出第  大的数字。
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 ;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值