NC73 数组中出现次数超过一半的数字
题意
给你一个数组,找出出现次数超过一半的数字。(也叫主元素问题)
1. 暴力法
枚举每一个数,看他是不是在数组中出现了超过一半的次数。
- 时间复杂度:
, 两重循环
- 空间复杂度:
.
2. 排序法
既然是众数且超过了一半,那么肯定也是中位数,排序后取中点即为所求。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int n = numbers.size();
sort(numbers.begin(), numbers.end());
return numbers[n>>1];
}
};- 时间复杂度:
. 依赖stl的sort方法。
- 空间复杂度:
3. 哈希表法
根据众数的定义,它出现的次数最多,所以用一个哈希表统计每个数字出现的次数,找最多的即可。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
unordered_map<int, int> m;
// 统计每个数字出现的次数
for (auto v : numbers) m[v]++;
// 找出现次数超过一半的
for (auto [k, v] : m) {
if (v > numbers.size()/2) return k;
}
// 兜底逻辑,没找到返回0
return 0;
}
};- 时间复杂度:
. 遍历一轮数组和一轮map。
- 空间复杂度:
. 定义了一个大小为
的map。
4. Boyer-Moore 投票算法(本题最佳算法)
这道题中,众数多了一个附加条件,出现的次数大于一半,那么说明该数比其他数字加起来出现的数都多。
Boyer-Moore 投票算法分为两步:
- 初始化两个变量,记录当前的候选值candidate和候选值出现的次数count。
- 第一轮遍历数组,如果count为0, 赋值当前元素予candidate,且count自加1; 如果元素与candidate相等,count自加1,否则自减1。
- 第二轮遍历数组,若candidate在数组出现次数大于数组size一半,则为多数元素,否则不存在多数元素。
对于本题,题目有一个已知条件,说明超过一半的众数一定存在,故第二轮遍历可省略。
如图所示:
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int res = 0, cnt = 0;
for (auto v : numbers) {
if (v == res) cnt++; // 遇到同样的数,票数+1
else {
cnt--; // 不同的数票数减一
if (cnt <= 0) res = v, cnt = 1; // 没有数了,则当前的数为候选人, 注意不能写=0, 否则第一个数的边界上会wa
}
}
// 第二轮遍历省略。
// cnt = 0;
// for (auto v : numbers) {
// if (v == res) cnt++;
// }
// if (cnt < numbers.size()/2) return 0;
return res;
}
};- 时间复杂度:
. 遍历一轮数组。
- 空间复杂度:
. 没有额外的数组定义

京公网安备 11010502036488号