1. 前言:多数元素问题的核心考察点
多数元素(Majority Element)问题在算法面试中出现的频率相当高,根据我的面试经验,几乎每三家技术公司中就有一家会在初面或笔试中考察这个经典问题。题目看似简单 - 找出数组中出现次数超过一半的元素 - 但它完美考察了两个关键能力:
- 时间复杂度优化意识:从最直观的O(n²)解法,逐步优化到O(nlogn)甚至O(n)的过程,体现了工程师对性能的敏感度
- 数学思维应用能力:最优解Boyer-Moore算法背后的数学原理,展示了如何将抽象问题转化为可计算的模型
我在第一次遇到这个问题时,掉进了multiset的陷阱,后来通过哈希表优化,最终被排序法的简洁震惊。更让我印象深刻的是Boyer-Moore算法 - 仅用O(1)空间就解决问题,这种思路的转变值得每个算法工程师体会。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解法一:多重集合的陷阱与教训
2.1 初始思路与实现
当我第一次看到这个问题时,最直观的想法是利用C++的multiset容器。multiset允许重复元素,并提供了count()方法直接统计元素出现次数。我的第一版实现是这样的:
cpp复制#include <set>
using namespace std;
int majorityElement(vector<int>& nums) {
multiset<int> ms(nums.begin(), nums.end());
for (int num : nums) {
if (ms.count(num) > nums.size() / 2) {
return num;
}
}
return -1; // 题目保证有解,这行不会执行
}
2.2 为什么这会超时?
在LeetCode上提交这个解法后,面对大规模测试用例时出现了超时。经过分析发现:
- multiset::count()的时间复杂度是O(log n + k),其中n是集合大小,k是目标元素出现次数
- 在最坏情况下(比如所有元素相同),count()需要遍历整个集合,时间复杂度退化为O(n)
- 外层还有对nums的遍历,整体复杂度达到O(n²)
关键教训:STL容器的接口复杂度不能想当然,必须查阅文档确认。count()这类"简单"操作在大数据量时可能成为性能瓶颈。
2.3 适用场景分析
虽然multiset解法在这里不适用,但它并非一无是处。在以下场景仍然有价值:
- 数据量小且需要自动排序的场景
- 需要频繁插入、删除而较少统计的场景
- 需要保持元素有序并快速查找上下界的场景
3. 解法二:哈希表的经典解法
3.1 优化思路的形成
意识到multiset的性能问题后,我转而考虑哈希表。哈希表的插入和查询平均都是O(1),理论上可以将整体复杂度降到O(n)。关键在于:
- 用unordered_map存储<元素,出现次数>对
- 遍历数组时实时更新计数
- 一旦发现某个元素计数超过n/2,立即返回
3.2 实现细节与优化
这是我的哈希表实现版本:
cpp复制#include <unor
