多数元素问题是算法题中的经典题型:给定一个长度为 n 的数组,其中一个元素出现次数 大于 n/2,需要在线性时间、常数空间内找出它。
例:
输入: [2,2,1,1,1,2,2]
输出: 2
题目保证多数元素一定存在。
核心思想:成对抵消,剩者为王
如果一个元素的出现次数超过一半,那么在与其它所有元素进行"成对抵消"后,它必然能够存活下来。
Boyer--Moore 投票算法正是基于这个思想:
-
遍历数组时维护两个量:
-
candidate:当前候选人 -
count:候选人的净票数
-
对每个数字 num:
-
若
count == 0,将候选人设为num。 -
若
num == candidate,count++(支持票)。 -
否则
count--(反对票,抵消一张支持)。
因为多数元素的票多于其它所有元素的总和,因此不可能被完全抵消,最终留下的 candidate 就是多数元素。
Java 代码(O(n) 时间 + O(1) 空间)
class Solution {
public int majorityElement(int[] nums) {
int candidate = 0;
int count = 0;
for (int num : nums) {
if (count == 0) {
candidate = num;
count = 1;
} else if (num == candidate) {
count++;
} else {
count--;
}
}
return candidate;
}
}
为什么算法有效?
把数组看作"选举":
-
多数元素拥有超过半数的票,无法被其它元素完全抵消。
-
抵消完所有成对元素后,剩下的一定就是多数元素。
整个过程只需一次遍历(线性时间),并且使用常量额外空间,非常高效。
总结
多数投票算法是一种优雅且高效的线性时间算法:
-
时间复杂度:O(n)
-
空间复杂度:O(1)
-
适用条件:多数元素保证存在
这是算法面试中极其常见的模板技巧,与"异或消对法"(如 LeetCode 136)一起,是必备基础工具。
如果你理解了"成对抵消、剩者为王"的直觉,这道题就再也不会忘记。