(Hash大数排序)Sort

题目描述:给你n个整数,请按从小到大的顺序输出其中前m大的数。

输入:每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含各不相同的,且大小处于[-500000,500000]的整数。

输出:对每组数据按从大到小的顺序输出前m大的数。

样例输入:

5   3

3 -35  92 213 -644

样例输出:

213 92 3


思考:在本例中,如果用排序来解决该题,由于待排序数字的数量十分庞大(1000000),即使使用时间复杂度为O(nlogn)的快排,其时间复杂度也达到了千万数量级,因此不能使用快排解决此题。

思路:由于输入数据中出现了负数,于是我们不能直接把输入数据当作Hash数组的下标来访问数组,而是将每一个输入的数据都加上一个固定的偏移值OFFSET,使得输入数据[-500000,500000]区间被映射到Hash数组下标的[0,1000000]区间。我们利用hash数组将所有出现过的数字(对应的数组元素,Hash的下标)都标记为1,当我们需要输出前m大个元素时,我们只需要从500000开始,降序遍历这个数组,,查找前m个标记成1的数组元素,输出其对应的下标数字即可。

#include <stdio.h>
#include <stdlib.h>
#define OFFSET 500000 //偏移量,用于补偿实际数字与数组下标之间偏移量
int Hash[1000001];//Hash数组,记录每个数字是否出现,不出现为0,出现为1
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
            int i;
        for(i= -500000;i<=500000;i++){
            Hash[i+OFFSET] = 0;
        }//初始化,将每个数字都标记为未出现
        for(i=0;i<n;i++){
            int x;
            scanf("%d",&x);
            Hash[x +OFFSET]=1;//凡是出现过的数字,该数组元素均为1
        }
        for(i=500000;i>=-500000;i--){ //输出前m个数,从Hash数组最末端判断
            if(Hash[i+OFFSET]==1){  //若出现过,在m不等于0之前,一定是前m个大数
                printf("%d",i);  //输出该数字
                m--; //输出一个数字后,m--,直至变为0
                if(m!=0) printf(" "); //注意格式,求m个数未被输出完毕,在输出的数字后紧跟一个空格
                else{
                    printf("\n");//若m个数字已经被输出完毕,则在输出的数字后面输出换行,并跳出程序
                    break;
                }
            }
        }
    }


    return 0;
}

注意:在输出的每一个数字之间存在一个空格,而在最后一个数字之后却不存在空格。


输入:每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含相同的,可能有重复的数字,且大小处于[-500000,500000]的整数。

#include <stdio.h>
#include <stdlib.h>
#define OFFSET 500000
int Hash[1000001];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
            int i;
        for(i= -500000;i<=500000;i++){
            Hash[i+OFFSET] = 0;
        }
        for(i=0;i<n;i++){
            int x;
            scanf("%d",&x);
            Hash[x +OFFSET]++;
        }
        for(i=500000;i>=-500000;i--){
            while(m>0&&Hash[i+OFFSET]--){
                    printf("%d",i);
                m--;
                if(m!=0) printf(" ");
                else{
                    printf("\n");
                    break;
                }
            }
        }
    }

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值