问题描述
小R从班级中抽取了一些同学,每位同学都会给出一个数字。已知在这些数字中,某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。
问题解析
- 给定一个数组,数组中的某个元素出现次数超过数组长度的一半。
- 找出这个多数元素。
关键点:
- 数组中一定存在一个多数元素,因为它的出现次数超过数组长度的一半。
这个问题是一个典型的“多数元素问题”,即在一个数组中找到出现次数超过数组长度一半的元素。代码实现采用的是一种高效算法——Boyer-Moore 投票算法。
Boyer-Moore 投票算法详解
算法思路:
-
核心原理:
- 如果我们假设多数元素存在,它的数量一定比其他所有元素的总和还要多。
- 因此可以通过一个计数器和一个候选变量,不断筛选掉非多数元素,最终找到多数元素。
-
具体步骤:
-
初始化计数器
count = 0和候选元素candidate = 0。 -
遍历数组:
- 如果计数器为
0,将当前数字设置为候选元素,并将计数器置为1。 - 如果当前数字等于候选元素,则计数器加
1。 - 如果当前数字不等于候选元素,则计数器减
1。
- 如果计数器为
-
遍历结束后,
candidate中存储的就是多数元素。
-
为什么这样有效?
- 假设数组长度为
n,多数元素出现次数超过n/2。每次计数器减少时,实际上在筛掉非多数元素。因此多数元素的累计数量一定会支撑它成为最后的候选值。
Boyer-Moore 投票算法是解决“多数元素问题”的经典方法,利用“计数器”的机制高效找到多数元素。此实现具有以下特点:
- 简单高效。
- 时间复杂度为 O(n),空间复杂度为 O(1)。
- 对于输入的合法性(如是否存在多数元素),题目保证了问题条件,因此无需额外验证。
代码实现
#include <iostream>
#include <vector>
using namespace std;
int solution(vector<int> array) {
int count=0;
int candidate=0;
for(int num:array){
if(count==0){
candidate=num;
count=1;
}else if(num==candidate){
count++;
}else{
count--;
}
}
return candidate;
}
int main() {
cout << (solution({1, 3, 8, 2, 3, 1, 3, 3, 3}) == 3) << endl;
cout << (solution({5, 5, 5, 1, 2, 5, 5}) == 5) << endl;
cout << (solution({9, 9, 9, 9, 8, 9, 8, 8}) == 9) << endl;
return 0;
}
关键步骤解释
-
初始化:
count初始化为0,candidate初始化为0。
-
遍历数组:
- 对于每个数字
num,检查count是否为0。如果是,将num设为candidate,并将count设为1。 - 如果
num与candidate相同,count加1。 - 如果
num与candidate不同,count减1。
- 对于每个数字
-
返回结果:
- 最终,
candidate就是我们要找的数字。
- 最终,