题目描述
解题
这题也不难,解法也很多:
- 哈希表统计法:遍历数组 nums,用 HashMap 统计各数字的出现次数,最终找出出现次数超过数组长度一半的数组元素。
- 数组排序法:将数组 nums 排序,由于需要找出出现次数超过数组长度一半的元素,那么数组中点的元素必然是这个我们要找的元素
- 摩尔投票法:核心理念为“正负抵消”;其实就是一换一。由于我们需要找出的元素是占有整个数组元素的一半以上,那么即使这个元素和其他元素进行“兑子”,最后剩下的依旧是这个元素。
这里重点记述摩尔投票法。
摩尔投票法:
- 票数和:我们需要找出的是出现次数超过数组长度一半的元素;若记这个元素的票数为 +1,记其他元素的票数为 -1,则一定会有所有数组元素的票数和 > 0
- 票数正负抵消:设数组 nums 中出现次数超过数组长度一半的元素为 x,数组长度为 n。若 nums 的钱前 a 个元素的票数和 = 0,则数组后 (n-a) 个元素的票数和依旧 > 0,即后 (n-a) 个元素中出现次数占一半的元素依旧是 x
算法原理:
- 为了构建正负抵消,我们假设数组的第一个元素 n1 为 x,遍历数组统计票数,当发生正负抵消时,剩余数组元素中,出现次数超过数组长度一半的元素也依然是 x(设真正出现次数超过数组长度一半的元素为 x),这是因为:
- 当 n1 = x 时,抵消的数字中,有一半是 x
- 当 n1 != x 时,抵消的数字中,少于或等于一半是 x
- 由此特性,每轮假设都可以缩小剩余数组区间。当遍历完成时,最后一轮假设的数字即为 x(由于 x 超过数组元素的一半,最后一轮的票数和必为正数)
算法流程:
- 初始化:票数统计 votes = 0,出现次数超过数组长度一半的元素为 x
- 循环抵消:遍历数组 nums 中的每一个数字;当票数 votes 等于 0,则假设当前 num 为 x;当 num = x 时,票数 votes 加 1,否则 减 1.
- 返回值:返回最后的 x 即可
class Solution {
public int majorityElement(int[] nums) {
int x = 0,votes = 0;
for(int num:nums){
if(votes == 0) x = num;
votes += num==x?1:-1;
}
return x;
}
}