数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
假设数组非空,并且一定存在满足条件的数字。
思考题:
- 假设要求只能使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢?
数据范围
数组长度 [ 1 , 1000 ] [1,1000] [1,1000]。
样例
c
输入:[1,2,1,1,3]
输出:1
**算法思路 **
** 摩尔投票算法(Moore Voting Algorithm) **
- 初始化 :维护一个候选值
val
和计数器cnt
,初始时val
为任意值(如 -1),cnt
为 0。 - 遍历数组 :
- 如果
cnt
为 0,则将当前数字x
设为候选值val
,并设置cnt = 1
。 - 如果当前数字
x
等于候选值val
,则cnt
加 1。 - 如果当前数字
x
不等于候选值val
,则cnt
减 1。
- 如果
- 返回结果 :遍历结束后,
val
即为出现次数超过一半的数字。
**关键点: **
- 摩尔投票算法的核心思想是 "抵消" 。出现次数超过一半的数字,最终一定会保留在
val
中,因为其他数字的出现次数总和不足以完全抵消它。 - 该算法假设输入数组 一定存在 出现次数超过一半的数字。如果题目不保证这一点,需要额外验证步骤(但本题已保证)。
指标 | 值 | 说明 |
---|---|---|
时间复杂度 | O(n) | 只需遍历数组一次,n 为数组长度。 |
时间复杂度 | O(1) | 只使用了常数级别的额外空间(val 和 cnt )。 |
cpp
class Solution {
public:
int moreThanHalfNum_Solution(vector<int>& nums) {
int val = -1, cnt = 0;
for(auto x : nums)
{
if(!cnt) val = x, cnt = 1;
else
{
if(val == x) cnt ++;
else cnt --;
}
}
return val;
}
};