三叶

1
2
3
4
数组中占比超过一半的元素称之为主要元素。给你一个 整数 数组,找出其中的主要元素。

输入:[1,2,5,9,5,9,5,5,5]
输出:5

摩尔投票 :在集合中寻找可能存在的多数元素,这一元素在输入的序列重复出现并占到了序列元素的一半以上;在第一遍遍历之后应该再进行一个遍历以统计第一次算法遍历的结果出现次数,确定其是否为众数;如果一个序列中没有占到多数的元素,那么第一次的结果就可能是无效的随机元素。

换句话说,每次将两个不同的元素进行「抵消」,如果最后有元素剩余,则「可能」为元素个数大于总数一半的那个。

具体的,我们定义一个变量 来保存那个可能为主要元素的值, 用来记录该值的出现次数。然后在遍历数组 过程中执行如下逻辑:

  • 如果 为 :说明之前出现过的 已经被抵消完了,更新一下 为当前值,出现次数为 :x = nums[i], cnt = 1
  • 如果 不为 :说明之前统计的 还没被抵消完,这是根据 与 是否相等进行计算即可:cnt += nums[i] == x ? 1 : -1

当处理完 之后,我们得到了一个「可能」的主要元素。注意只是可能,因为我们在处理过程中只使用了 xcnt 来记录,我们是无法确定最后剩下的 是经过多次抵消后剩余的主要元素,还是只是不存在主要元素的数组中的无效随机元素。

因此我们需要再进行一次遍历,检查这个「可能」的主要元素 的出现次数是否超过总数一半。

O(1) 找众数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public int majorityElement(int[] nums) {
int n = nums.length;
int x = -1, cnt = 0;
for (int i : nums) {
if (cnt == 0) {
x = i;
cnt = 1;
} else {
cnt += x == i ? 1 : -1;
}
}
cnt = 0;
for (int i : nums) if (x == i) cnt++;
return cnt > n / 2 ? x : -1;
}
}