今天在做题的时候遇到一个比较有意思的题目,在这里分享给大家,同时介绍一下这个算法。如果大家是在网上买课学习算法知识的话很容易忽视掉这个点(虽然这个知识点考的也不是很频繁)。虽然CSDN上也有这个算法的讲解,但我看了一下都不是特别详细,所以还是打算详细地介绍一下这个算法。
题目
给定一个大小为的整数数组,这个数组满足条件
:数组中一定存在一个元素,它的出现次数大于其他所有元素的出现次数之和(注意是严格大于)。请你找出这个数。
输入格式:共两行,第一行,一个整数,表示整数数组的大小。接下来一行有
个整数。输出格式:共一行,输出找到符合题目要求的那个数。
数据范围:,对于数组的每一个元素
,都有:
。要求:时间限制:
。空间限制:
。
常见思路
接下来,我们先介绍几种常见的解题思路:
暴力搜索
首先我们自然而然地可以想到用暴力搜索的方法。我们统计每个元素出现的次数,然后输出出现次数最多的那个元素。
#include <iostream>
#include <unordered_map>
#include <vector>
std::unordered_map<int, int> countElements(const std::vector<int>& arr) {
std::unordered_map<int, int> counts;
for (int element : arr) {
if (counts.find(element) != counts.end()) {
counts[element]++;
} else {
counts[element] = 1;
}
}
return counts;
}
int main() {
std::vector<int> array;
std::unordered_map<int, int> elementCounts = countElements(array);
int n;
scanf("%d",&n);
while(n--){
int x;
scanf("%d",&x);
array.push_back(x);
}
for (const auto& pair : elementCounts) {
if(pair.second>n/2){
printf("%d",pair.first);
break;
}
}
return 0;
}
快排
我们注意到,对于一个已经排好序的数组,如果一个元素出现的次数超过数组大小的一半,那么这个数组中间的元素一定就是我们要找的元素,因此可以有如下代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int>arr;
int main()
{
int n;
scanf("%d",&n);
int p=n;
while(p--){
int x;
scanf("%d",&x);
arr.push_back(x);
}
sort(arr,arr+n);
printf("%d",arr[n/2]);
return 0;
}
然而,上述两种方法我们都要存入整个数组。而10的7次方个int的大小大约在40MB左右,远远大于题目要求,因此我们需要一种别的方法。
摩尔投票算法
接下来我们要介绍本篇文章的重点:摩尔投票算法。
下面我们先说明摩尔投票算法的步骤:
- 定义一个计数器counter和标记X,两者均初始化为0 。
- 当读入一个数y时,如果counter==0 。那么X=y
- 如果X==y ,那么counter++
- 如果X!=y ,那么counter--
接下来我们来说明一下为什么这个算法可行。
首先,很显然,当计数器 时,表明标记X在当前已读到的所有数中出现频率大于一半,反之亦然。
接下来最关键的是第二步的操作。注意到:在当counter==0时表示众数正好占所有数的一半,因此,如果读入的数y和X一样,那么赋不赋值都无所谓;如果不一样,读入y后X的频率就会小于一半,因此X一定不是我们要找的数。
那y有没有可能是我们要找的数呢。我们注意到,此时X已经有n/2-1个,还剩下n/2+1个,如果这歌数组满足条件A,那么剩下的所有元素就必须是y。
因此我们得出结论,按照摩尔投票算法的步骤,如果这个数组满足条件A,那么标记X一定就是我们想要找的数。
当然,我们是一个一个数的读入,因此数组不可能在一直满足条件A。但这无所谓,因为我们只需要最后整个数组满足条件A即可,中间步骤无论X变成什么都无所谓。
代码
最后我们附上这道题的代码。
#include<iostream>
int main(){
int counter=0,X=0;
int n;
scanf("%d",&n);
while(n--){
int y;
scanf("%d",y);
if(counter==0) X=y;
if(X==y)counter++;
else counter--;
}
printf("%d",X);
return 0;
}