c++面试题(24)-----数组中出现次数超过一半的数字
- 操作系统:ubuntu22.04
- IDE:Visual Studio Code
- 编程语言:C++11
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组非空,并且一定存在满足条件的数字(即一定有一个数字出现次数超过一半)。
示例:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
解法一:摩尔投票法(最优解,时间 O(n),空间 O(1))
这是本题的最佳解法,利用“抵消”思想。
🧠 核心思想:
- 设一个候选数 candidate 和计数器 count;
- 遍历数组:
- 如果 count == 0,更新候选人为当前数;
- 如果当前数等于候选人,count++;
- 否则 count–;
- 最终留下的候选人就是我们要找的“出现次数超过一半”的数字。
因为题目保证存在,所以不需要额外验证。
实现代码
#include <vector>int findMost( std::vector< int > nums )
{// 候选人int candidate = nums[ 0 ];// 投票计数器int count = 1;for ( int i = 1; i < nums.size(); ++i ){if ( nums[ i ] == candidate ){// 相同数字,票数加一count++;}else{// 不同数字,票数减一count--;// 票数归零,更换候选人if ( count == 0 ){candidate = nums[ i ];count = 1;}}}// 因为题目保证存在,所以直接返回候选人即可return candidate;
}int main()
{std::vector< int > nums = { 1, 3, 2, 2, 2, 2, 6 };int count = findMost( nums );std::cout << count << std::endl;
}
运行结果
2
解法二:哈希表统计(次优解,时间 O(n),空间 O(n))
遍历数组,使用哈希表记录每个数字出现的次数,最后找到出现次数大于 n/2 的那个数字。
示例代码:
int findMost( std::vector< int >& nums )
{std::unordered_map< int, int > freq;for ( int num : nums ){freq[ num ]++;if ( freq[ num ] > nums.size() / 2 )return num;}return -1; // 不会执行到这里(题目保证存在)
}
解法三:排序取中位数(时间 O(n log n),空间 O(1) 或 O(n))
将数组排序后,中间位置的元素一定是出现次数超过一半的数字(因为其至少占一半+1)。
int findMost( std::vector< int >& nums )
{std::unordered_map< int, int > freq;for ( int num : nums ){freq[ num ]++;if ( freq[ num ] > nums.size() / 2 )return num;}return -1; // 不会执行到这里(题目保证存在)
}