A - 众数问题--SDUT

A - 众数问题

Description

给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为众数。例如,S={1,2,2,2,3,5}。多重集S的众数是2,其重数为3。对于给定的由n 个自然数组成的多重集S,计算S的众数及其重数。如果出现多个众数,请输出最小的那个。

Input

输入数据的第1行是多重集S中元素个数n(n<1300000);接下来的n行中,每行有一个最多含有5位数字的自然数,。

Output

输出数据的第1行给出众数,第2行是重数。

Sample

Input 

6
1
2
2
2
3
5

Output 

2
3

 

众数问题是一个老问题了,不用分治思想一样可以解决,在数据量较小的情况下,二者的区别微乎其微,但是当数据量巨大时,基于分治思想的代码相比之下就会快很多,并且单纯对本题来说,所给的运行时间为2000ms,最基本最简单的方法也不会TLE,这里给出两种方法,两种都可以AC的代码。具体解释对应在具体代码中。

方法一:最为基本的方法,在宏观上定义一个可以存十万数据量的数组,因为本题的n的值为不超过五位数的自然数,我一开始定义了一个百万级的数组,后来一想没必要,最大的数据值不过99999,虽然最多会有一百三十万的数据流入数组,但是填满数组之后剩下的都是重复的数据,所以定义十万的数组即可。初始化数组之后,将每次输入的n的值存入对应的数组格中,即a[n]++。然后不断比较a[i]中的数据,大的数据替换小的数据即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int a[100000];
int main()
{
	memset(a,0,sizeof(a));//初始化数组,初始值都赋为0 
	int n,num;
	int mode,mul=0;//mode代表众数,mul代表重数 
	cin>>n;
	for(int i=0;i<n;i++)//对应的位置++ 
	{
		cin>>num;
		a[num]++;
	}
	for(int i=0;i<100000;i++)
	{
		if(a[i]!=0&&mul<a[i])//发现mul比a[i]中的数据小时,重新改写mode以及mul的值 
		{
			mul=a[i];
			mode=i;
		}
	}
	cout<<mode<<endl;//输出 
	cout<<mul<<endl;
	return 0;
}

方法二:

采用分治思想 将数组中的元素进行顺序排列之后,得到的新序列,从中间开始一分为二,左边一部分,右边一部分,分别比较左右数据的值,有与mid数据一样的继续遍历,直到遇到第一个不等于mid数据的值,break跳出循环,这样左边与mid相等的值就找完了(一定要时刻记住我们是遍历的排好序的数组,一样的一定在一起,不相等的之后一定不相等)。再for循环右边的一部分,同样,不同的数据就跳出循环。此时要进行众数和重数的更新,更新之后要判断是否继续递归函数进行众数的寻找,因为一组数据可能有多个重数相等的众数。判断的依据是根据跳出时指针的位置到左或右边界的距离,如果距离大于重数的值就要进行函数的递归继续寻找众数,如果距离小于等于重数的值就不需要进行递归,因为即使有众数,重数的值也不会比现在的大,所以当前的重数与众数即为正确答案。如果还是不好理解看代码注释。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int mode,mul,n;
void mode_function(int a[],int l,int r)//定义众数寻找函数 
{
	int mid=(l+r)/2;//分治思想,从中间开始 
	int num=1;//每个数的重数起始值就为1 
	int i,j;//用来判断是否需要继续进行函数的递归 
	for(i=mid-1;i>=l;i--)//从mid的左边的第一个数开始进行遍历,一直到最左端 
	{
		if(a[i]==a[mid])//如果相等,则重数num++ 
		{
			num++;
		}
		else
		{
			break;//否则break跳出函数即可 
		}
	}
	for(j=mid+1;j<=r;j++)//从mid的右边第一个数开始进行遍历,一直到最右端 
	{
		if(a[j]==a[mid])//如果相等,直接跳出 
		{
			num++;
		}
		else
		{
			break;
		}
	}
	if(num==mul&&mode>a[mid])//条件判断。用于递归途中,碰到两组重数个数相等,但是众数值比中间值大的情况
	//如果重数的个数等于mul(初始值为0) ,则更新mode以及mul的值 
	{
		mul=num;
		mode=a[mid];
	}
	//条件判断,与上述判断不同的是,此步判断用于 开始状态,mul很少,但是上述循环中遍历出了很多重数的情况 
	if(num>mul)
	{
		mul=num;
		mode=a[mid];
	}
	//因为是排序好的序列,所以如果从左到i(因为a[i]!=a[mid]而break出循环的i的值)的值小于等于重数mul的数值
	//那么左边就不需要再进行遍历 ,因为左边必定没有当前众数的重数大 
	if(i-l>mul)
	{
		mode_function(a,l,i);
	}
	if(r-j>mul)//同上 
	{
		mode_function(a,j,r);
	}
 } 
int main()
{
	cin>>n;
	int a[n+9];//比n值大一些就好,防止数据溢出。不要大太多 
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	mul=mode=0;
	sort(a,a+n);//STL函数库中的排序函数 
	mode_function(a,0,n-1);//调用众数查找函数 
	cout<<mode<<endl;//输出 
	cout<<mul<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值