题目传送门:【BZOJ 2456】
题目大意: 给你一个 n 个数的数列,其中某个数出现了超过 n/2 次即为众数。请你找出那个数。数据保证存在这样的众数。
时间限制:1 Sec
空间限制:1 MB
题目分析:
又是最近才考过的题的“原版”。果然“原版”要简单多了,比考试的题代码要少好几十行。。。
由题,这道题的难点在于空间限制,仅 1MB 的空间意味着我们不能用普通的“数组保存法”解决这道题。观察题目性质,这道题只需要让我们求出哪一个数是众数就行了,并且这里的众数出现次数还超过了 n/2。
那么这里我们就有一个好方法了:有一种叫做“抵消”的思想,我们将其类比在这道题上。因为其他所有的数出现次数之和都小于这里的众数,所以,假设每一个其他的数都可以与这个众数相互“抵消”掉,那么最后这个众数肯定还有剩余。到了这里,我们就可以很好地搞定这道题了:用一个 struct,里面存两个变量:一个是 id,表示当前可能的众数是什么;另一个是 cnt,表示当前可能的众数出现的次数(不是字面意思)。
具体的操作是这样的:我们先把 cnt 初始化为 0,在读入所有的数的过程中,设当前读入的数为 x;如果 cnt==0,那么就令 id=x,cnt=1;否则,若 id==x,则 cnt++,如果不等于,cnt–。最后输出保存下来的 id 值即可。
那么它的核心思想是什么呢?就是用了一种“优先队列”的思想。在这里因为空间不够多,我们就把队列压缩成了两个单独的变量,本质上是相似的。
下面附上代码:
- #include<cstdio>
- struct Num{
- int id,cnt; //id:众数的编号 cnt:这个数出现的次数
- }num;
- int n,a;
- int main(){
- scanf(”%d”,&n);
- for (int i=1;i<=n;i++){
- scanf(”%d”,&a);
- if (a!=num.id)
- if (num.cnt>1) num.cnt–;
- else num.id=a,num.cnt=1;
- else num.cnt++;
- }
- printf(”%d”,num.id);
- return 0;
- }