北京大学openjudge 输出前m大的数

注:引用郭炜老师的著作。

描述

   给定一个数组包含n个元素,统计前m大的数并且把这m个数从大到小输出。

input:

      第一行:包含一个整数n,表示数组的大小。n < 100000。

      第二行:包含n个整数,表示数组的元素,整数之间以一个空格分。每个整数的绝对值不超过100000000

      第三行:包含一个整数mm < n

output

      从大到小输出前m大的数,数据间用逗号隔开

    

解题思路:如果先排序再从搜索,那么时间复杂度就是:nlogn + m。速度达不到笔者的要求,那有没有更快的呢?

当然有了(不然到这不就结束了吗。笔者又怎么会舍得可爱的你就这么失望离开)。我们可以把前m大的数放在数组的最右边,然后对最后m个数排序输出就可以了。

关键:在O(n)时间内实现把前m大的数放在数组的最右面。

 

引入操作 arrangeRight(k): 把数组(或数组的一部分)前k大的

都弄到最右边

1)设key=a[0], key挪到适当位置,使得比key小的元素都在

      key左边,比key大的元素都在key右边(线性时间完成

2) 选择数组的前部或后部再进行 arrangeRight操作。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 100001
using namespace std;

void swap(int &a,int &b){
    int tmp = a;
    a = b;
    b = tmp;
}
void arrangeRight(int a[],int s,int e,int p)
{
    if(s >= e)
        return;
    int k = a[s];
    int i = s;
    int j = e;
    while(i != j){
        while(j > i&&a[j] >= k){
            --j;
        }
        swap(a[i],a[j]);
        while(i < j&&a[i] <= k){
            ++i;
        }
        swap(a[i],a[j]);
    }
    int num = e-i+1;
    if(num == p)
        return;
    else if(num > p){
        arrangeRight(a,i+1,e,p);
    }
    else{
        arrangeRight(a,s,i-1,p - num);
    }
}
int main()
{
    int n,m;
    int a[maxn];
    cin>>n;
    for(int i = 0;i < n;i++){
        cin>>a[i];
    }
    cin>>m;
    arrangeRight(a,0,n-1,m);
    sort(a+n-m,a+n,greater<int>() );
    for(int i = n-m;i<n;i++){
        cout<<a[i]<<endl;
    }
    return 0;
}

 

 

猜你喜欢

转载自blog.csdn.net/qq_42018521/article/details/81482545