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;
}