题目
小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
思路
要解决这个问题,可以使用摩尔投票算法(Boyer-Moore Voting Algorithm),它能够在O(n)的时间复杂度内找到出现次数超过一半的数字。这个算法的基本思路是通过维护一个候选数字和计数器来判断哪个数字可能是众数。
demo
#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 = 1;
} else if (num == candidate) {
count++;
} else {
count--;
}
}
// 第二遍遍历,确认候选数字的出现次数是否超过一半
count = 0;
for (int num : array) {
if (num == candidate) {
count++;
}
}
// 如果候选数字的出现次数超过一半,返回该数字
if (count > array.size() / 2) {
return candidate;
}
return 0; // 如果没有找到,返回0(或其他指示值)
}
int main() {
// 添加测试用例
cout << (solution({1, 3, 8, 2, 3, 1, 3, 3, 3}) == 3) << endl;
return 0;
}
使用AI练中学可以更快地找到代码的不足之处,帮助我们更快地AC。
代码解释
-
候选数字的选择:
- 我们使用两个变量:
candidate(候选数字)和count(计数器)。 - 遍历数组,如果
count为0,则将当前数字设为候选数字,并将count设为1。如果当前数字与候选数字相同,则count加1;否则,count减1。
- 我们使用两个变量:
-
确认候选数字:
- 在第二次遍历中,我们统计候选数字在数组中出现的次数。
- 如果出现次数超过数组长度的一半,则返回该候选数字。
这个算法的优点是时间复杂度为O(n),空间复杂度为O(1),非常高效。
扩展:巩固算法知识
摩尔投票算法(Boyer-Moore Voting Algorithm)是一种用于寻找数组中出现次数超过一半的元素(众数)的高效算法。它的时间复杂度为O(n),空间复杂度为O(1),非常适合处理此类问题。下面详细介绍该算法的原理和实现步骤。 AI陪练相当不错,也会帮忙扩展相应的知识:
算法原理
摩尔投票算法的核心思想是利用“抵消”机制来找到候选众数。具体步骤如下:
-
候选者选择:
-
初始化一个候选者(
candidate)和一个计数器(count)。 -
遍历数组中的每个元素:
- 如果
count为0,说明当前没有候选者,将当前元素设为候选者,并将count设为1。 - 如果当前元素等于候选者,
count加1。 - 如果当前元素不等于候选者,
count减1。
- 如果
-
通过这种方式,最终的候选者就是可能的众数。
-
-
验证候选者:
- 在找到候选者后,需要再次遍历数组,统计该候选者的出现次数。
- 如果出现次数超过数组长度的一半,则返回该候选者;否则,返回一个指示值(如0或-1),表示没有众数。
代码实现
以下是摩尔投票算法的C++实现:
#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 = 1;
} else if (num == candidate) {
count++;
} else {
count--;
}
}
// 第二遍遍历,确认候选数字的出现次数是否超过一半
count = 0;
for (int num : array) {
if (num == candidate) {
count++;
}
}
// 如果候选数字的出现次数超过一半,返回该数字
if (count > array.size() / 2) {
return candidate;
}
return 0; // 如果没有找到,返回0(或其他指示值)
}
int main() {
// 添加测试用例
cout << (solution({1, 3, 8, 2, 3, 1, 3, 3, 3}) == 3) << endl;
return 0;
}
代码解释
-
候选者选择:
- 在第一次遍历中,我们通过
count来跟踪当前候选者的有效性。每当count为0时,说明之前的候选者被抵消掉了,当前元素成为新的候选者。
- 在第一次遍历中,我们通过
-
验证候选者:
- 在第二次遍历中,我们统计候选者的出现次数,确保它确实是众数。
优缺点
-
优点:
- 时间复杂度为O(n),只需遍历数组两次。
- 空间复杂度为O(1),不需要额外的存储空间。
-
缺点:
- 该算法假设存在一个众数,如果没有众数,返回的候选者可能不正确。因此,必须进行第二次遍历来验证候选者的有效性。
应用场景
摩尔投票算法广泛应用于需要找出众数的场景,如投票系统、数据分析等。它的高效性使其在处理大规模数据时非常有用。