openjudge k大数

题目链接:3:k大数

总时间限制: 10000ms 内存限制: 655360kB


描述
求互异整数序列中第k大的数

输入
第一行 一个正整数n<5,000,000,表示序列长度

第二行 一个正整数0<=k后面n行每行一个整数。


输出

序列中第k大的数(对于最小的数k=0)


【题目分析】

这是一个经典的求第K大的数的问题。首先看时间要求,看起来nlog(n)的时间复杂度的算法是可以的。所以首先考虑直接排序:

#include<stdio.h>
#include<stdlib.h>

int In[6000000];

int comp(const void * a, const void * b)
{
	return *(int *) a - *(int *) b;
}

int main ()
{
	int n,k;
	scanf("%d%d", &n, &k);
	for (int i = 0; i < n; i++)
		scanf("%d",&In[i]);

	qsort(In, n, sizeof(int), comp);

	printf("%d\n",In[k]);

	return 0;
}

发现就已经可以过了。但人得有点追求不是嘛~考虑到输入都在int的范围,范围比较小。于是设计了如下的最坏情况为n(1+logt-logn)的算法(t为输入数值的大小范围。)

#include<stdio.h>

int In[6000000];
int temp1[6000000], l1;
int temp2[6000000], l2;


int main ()
{
	int n,k;
	scanf("%d%d", &n, &k);
	for (int i = 0; i < n; i++)
		scanf("%d",&In[i]);

	int * N = In, *t1 = temp1, *t2 = temp2;
	int * tt;
	int ln = n;
	while(1)
	{
		int Max = 0x80000000;
		int Min = 0x7fffffff;

		for (int i = 0; i < ln; i++)
		{
			if (Max < N[i])
				Max = N[i];
			if (Min > N[i])
				Min = N[i];
		}
		int Mid = (Max + Min) / 2;

		if (k == 0)
		{
			printf("%d\n", Min);
			break;
		}
		if (k == ln - 1)
		{
			printf("%d\n", Max);
			break;
		}

		l1 = 0; l2 = 0;

		for (int i = 0; i < ln; i++)
		{
			if (N[i] <= Mid)
			{
				t1[l1] = N[i];
				l1++;
			}
			else
			{
				t2[l2] = N[i];
				l2++;
			}
		}

		if (k >= l1)
		{
			k -= l1;
			tt = N; N = t2; t2 = tt;
			ln = l2;
		}
		else
		{
			tt = N; N = t1; t1 = tt;
			ln = l1;
		}
	}

	return 0;
}
接下来又注意到这道题输入的数据范围在0~100000000之间,并且两两不重复。于是设计了如下基于桶排序的方法,最坏时间复杂度k+t(t为数据范围,k为输入的那个k)

#include<stdio.h>

bool B[100000000];

int main ()
{
	int n,k;
	scanf("%d%d", &n, &k);
	for (int i = 0; i < n; i++)
	{
		int t;
		scanf("%d",&t);
		B[t] = 1;
	}

	int count = 0;

	for (int i = 0;;i++)
	{
		if (B[i])
			count++;
		if (count == k + 1)
		{
			printf("%d",i);
			break;
		}
	}

	return 0;
}

最后,一时无聊,决定把这道题玩坏。于是把上面的桶排序的代码改到了140字节:

#include<stdio.h>
int n,k,t,B[99999999];main(){scanf("%d%d",&n,&k);while(n--)scanf("%d",&t),B[t]=1;for(k++;k;)k-=B[n],k?n++:printf("%d",n);}



需要注意的是,k表示的是这组数中从小数的第k个数。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值