开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情
Day31 2023/02/06
难度:简单
题目
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:n≤50000,数组中元素的值 0≤val≤10000
要求:空间复杂度:O(1),时间复杂度:O(n)
输入描述:
保证数组输入非空,且保证有解
示例
输入:[1,2,3,2,2,2,5,4,2]
返回值:2
思路一
使用哈希法,遍历一遍数组然后,用map记录每一个元素出现的次数,然后再遍历一遍map,找出众数(即出现次数大于数组长度的一半)。
思路二
使用Boyer-Moore 投票算法,也是本题的最优解,当数组中两数不相等就消除,由于本题要求数组中一定有出现次数大于数组长度一半的元素,所以最坏情况每次都消去一个众数和一个非众数,最后留下的就是众数。
具体步骤:
- 初始化:候选人condidate = numbers[0], 候选人的投票次数count = 1;
- 遍历数组,如果当前数=condidate,则count++,否则count--,如果count=0, 表示没有候选人,则选取下一个数为候选人
- 直到数组遍历完毕,返回candidate
关键点
- 当元素出现次数记录完毕后,寻找众数的时候仍然是循环数组,因为数组中的元素是record的key值。
算法实现
c++代码实现-哈希法
#include <unordered_map>
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
unordered_map<int, int> record; //记录
for (int val : numbers) record[val]++; //记录次数
for (int val : numbers) { //找出众数
if (record[val] > numbers.size() >> 1) return val;
}
return 0;
}
};
- 时间复杂度 --- 遍历了一遍数组,n为数组长度
- 空间复杂度 --- 最坏情况下数组中元素各不相同,这时record数组中存储了n个元素
c++代码实现-Boyer-Moore投票算法
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int candidate = numbers[0]; //初始化为数组第一个元素
int count = 1; //计数器
for (int i = 1; i < numbers.size(); i++) {
if (numbers[i] == candidate) { //如果相同count++
count++;
} else { 否则count--
count--;
}
if (count == 0) { //等于零就让candidate为下一个元素
candidate = numbers[i + 1];
count++;
}
}
return candidate;
}
};
- 时间复杂度 --- 只需要遍历一遍数组,n为数组长度
- 空间复杂度 ---无额外的辅助空间
总结
- 我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法,但是哈希法是一种时间换空间的方法,使用的时候要考虑空间复杂的限制。