问题描述
小R从班级中抽取了一些同学,每位同学都会给出一个数字。已知在这些数字中,某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。
测试样例
样例1:
输入:
array = [1, 3, 8, 2, 3, 1, 3, 3, 3]
输出:3
样例2:
输入:
array = [5, 5, 5, 1, 2, 5, 5]
输出:5
样例3:
输入:
array = [9, 9, 9, 9, 8, 9, 8, 8]
输出:9
先贴个可运行代码:
#include <iostream>
#include <vector>
using namespace std;
int solution(vector<int> array) {
int candidate = 0;
int count = 0;
for (int num : array) {
if (count == 0) {
candidate = num;
}
count += (num == candidate) ? 1 : -1; //如果是candidate 就+1 反之-1
}
count = 0;
for (int num : array) {
if (num == candidate) {
count++;
}
}
if (count > array.size() / 2) {
return candidate;
} else {
return -1;
}
}
int main() {
cout << (solution({1, 3, 8, 2, 3, 1, 3, 3, 3}) == 3) << endl;
return 0;
}
使用了摩尔投票算法(Boyer-Moore Voting Algorithm)来解决这个问题。摩尔投票算法是一种高效的算法,用于在数组中找到出现次数超过一半的元素。
-
初始化候选者和计数:
- 首先初始化了一个候选者
candidate和一个计数count。候选者用于存储当前可能的多数元素,计数用于记录该候选者出现的次数。
- 首先初始化了一个候选者
-
第一遍遍历数组:
-
通过一个循环遍历数组中的每个元素。在每次迭代中,检查当前计数
count是否为零:-
如果
count为零,表示当前没有候选者,将当前元素设为候选者,并将计数设为1。 -
如果
count不为零,比较当前元素与候选者:- 如果当前元素等于候选者,增加计数。
- 如果当前元素不等于候选者,减少计数。
-
-
这一遍遍历的目的是通过抵消的方式找出可能的多数元素。
-
-
验证候选者:
- 在第一遍遍历结束后,候选者
candidate可能是多数元素,但也可能不是。因此,你需要进行第二遍遍历来验证候选者的出现次数是否确实超过数组长度的一半。 - 你再次遍历数组,统计候选者
candidate出现的次数。
- 在第一遍遍历结束后,候选者
-
检查计数并返回结果:
-
在第二遍遍历结束后,检查候选者的出现次数是否超过数组长度的一半:
- 如果超过,返回候选者
candidate。 - 如果没有超过,返回
-1(虽然题目保证存在这样的数字,理论上不会执行到这里)。
- 如果超过,返回候选者
-
来讨论一下如何使用暴力法来解决这个问题。暴力法通常是指通过遍历所有可能的组合或情况来找到问题的解。在这个问题中,我们可以通过遍历数组并统计每个数字的出现次数来找到出现次数超过一半的数字。
暴力法思路
-
理解问题:我们需要找到一个数字,它在数组中出现的次数超过数组长度的一半。
-
数据结构选择:可以使用哈希表(字典)来记录每个数字的出现次数。
-
算法步骤:
- 遍历数组,统计每个数字的出现次数。
- 检查每个数字的出现次数,如果某个数字的出现次数超过数组长度的一半,则返回该数字。