剑指 Offer 39. 数组中出现次数超过一半的数字

原题链接


题目描述

在这里插入图片描述


解题

这题也不难,解法也很多:

  • 哈希表统计法:遍历数组 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 超过数组元素的一半,最后一轮的票数和必为正数)

算法流程

  1. 初始化:票数统计 votes = 0,出现次数超过数组长度一半的元素为 x
  2. 循环抵消:遍历数组 nums 中的每一个数字;当票数 votes 等于 0,则假设当前 num 为 x;当 num = x 时,票数 votes 加 1,否则 减 1.
  3. 返回值:返回最后的 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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值