计算机的本质(LevOJ P1541)

我就先不多啰嗦了,题目内容如下。

题目描述

苦逼运维修好学校的土豆服务器,复读终止;

但一位恶人及时地将服务器下锅,开始复读。

现在服务器输出了n (1<=n<=200000) 个数,需要求出其中出现次数最多的那个数 x。

其中x出现的次数 c > n / 2, 非常符合复读机本质。

由于服务器已经下锅,运行混乱,对于任意输出的数u, 0<=u<=10^100。

输入描述

第1行一个整数n。

第2行n个整数,代表输出的整数。

本题只有一组测试数据。

输出描述

一个整数x。

样例输入

10

6 6 6 7 7 7 7 7 7 7

样例输出

7

不难看出,这是典型的主元素问题,其中主元素的个数严格大于 n / 2 。

这个题目的特殊之处就是数据的范围是0<=u<=10^100,对于这种大数问题,用int类型或者long long int类型是远远不够的,int类型的范围也就是21亿这样子,long long int类型也多不到哪去,远远小于给定范围。所以这个范围对使用C/C++的用户来说,就几乎等于告诉你这题的数据要用字符串来处理。

首先,我们来说一下数据在int范围内的解法。容易想到,先将给定数据排序,由于主元素个数严格大于 n / 2 ,就不难看出不论元素总的个数是奇数还是偶数,处于 n / 2 这个位置的元素必定是主元素。这样来看,最终的时间复杂度就由排序的时间复杂度来决定,快速排序复杂度是O(nlogn),用这种排序法便可以较快得出结果。

然后,我们只要对快速排序的过程稍作修改,将数据的比较改成字符串的比较,借助strcmp()这个函数,再者就是在字符串交换时借助strcpy()函数,当然使用这两个函数之前要包含字符串头文件。这样做完之后,我兴奋地提交了一次,然而结果是超时了QAQ。

我想,既然快速排序法超时了,这个题目必定就有更巧妙地算法。我考虑了一会,便想到了一个非常节省时间的方法,将时间复杂度降到了O(n), 提交的结果也很是让人激动,Accepted。

话不多说,先贴上代码为敬。

#include <stdio.h>  
#include <string.h>

char a[210000][110];
	
int main()  
{  
	char temp[110];
	int n,i,head;
        scanf("%d",&n);
        head=1;
	for (int i=1; i<=n;i++)
	{ 
    	scanf("%s",temp);  
    	if(head==1)
    		strcpy(a[head++],temp);
    	else if(strcmp(temp,a[head-1])==0)
    		strcpy(a[head++],temp); 
    	else
    		head--;
	}
        printf("%s\n",a[1]);  
		
	return 0;
}

这个方法就是采用删除法(或者说是抵消法),只要输入的下一个数和前一个数不同,就把这两个数都删除掉(或者说这两个数互相抵消),然后由于主元素的个数严格大于 n / 2 ,不难想到最终剩下的元素都是主元素,所以只要输出第一个元素就是最终结果。

好了,饺子对这个题目的理解目前就这么多,希望大佬们给出更妙的解法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值