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

题意

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

题解

常见的有三种解法

  1. 哈希表统计法:遍历数组,用map来统计各数字的数量,即可找出众数,时间复杂度和空间复杂度均为 O ( n ) O(n) O(n)
  2. 数组排序法:将数组排序,数组中点元素一定为众数
  3. 摩尔投票法:核心理念为票数正负相抵,此方法时间复杂度和空间复杂度分别为 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)

摩尔投票法

假设数组的众数为x,数组长度为n

简单理解就是,对众数投的票为+1,对其他数投的票为-1

众数出现的次数超过了数组长度的一半,因此如果遍历数组进行投票,最终的票数之和肯定大于0,而且如果前 m 个元素票数之和等于 0,数组后 n-m个元素的票数肯定大于0,即后 n-m 个元素的众数也是 x

但是我们事先并不知道众数是那个,我们假设数组首个元素 n1 为众数,遍历并统计票数。当发生票数之和为0时,剩余数组的众数一定不变 ,这是由于:

  • 如果n1是众数,抵消的数字中有一半是众数
  • 如果n1不是众数,那么抵消的数字中 n1占一半,其他数(有可能包括真正众数)占一半,因此,抵消的数字中少于或等于一半是众数

利用此特性,每轮假设发生票数和为0都可以缩小剩余数组区间。当遍历完成时,最后一轮假设的数字即为众数。

算法流程:

  1. 初始化:票数统计 votes = 0,众数 x ;
  2. 循环:遍历数组 nums 中的每个数字 num
    1. 当票数 votes 等于0,则假设当前数字 num 是众数
    2. num = x 时,票数 votes 自增 1 ;当 num != x 时,票数 votes 自减 1 ;
  3. 返回值:返回 x 即可
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int x = 0, votes = 0;
        for(int num : nums){
            if(votes == 0) x = num;
            votes += num == x ? 1 : -1;
        }
        return x;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值