LeetCode每日一题 229. 求众数 II

229. 求众数 II

Tag: Array

Difficulty: Medium

Link: https://leetcode-cn.com/problems/majority-element-ii/

分析

要求一个数组中所有超过[n/3](向下取整)的元素,比较容易想到的是用map方法,统计每个不同元素的数量,但是本题要求用O(1)的空间复杂度。所以这里需要一个新的方式——摩尔投票法

摩尔投票法解决的问题是,在任意多的候选人中,选出票数超过一半的的那个人。

它表明这样的规律:在任何数组中,出现次数大于该数组长度一半的值只能有1

假如有这样的数组表示投票 [A, B, C, A, A]

第一次遍历:抵消阶段

选择第一张票作为候选人,[A, 1]

第二张票与第一张票抵消, [A, 0]

第三张票与第一张票不同,并且计数为0,替换,[C, 1]

第四张票抵消 [C, 0]

第五张票替换 [A, 1]

最后获取A为可能的候选人

第二次遍历:计数阶段

注意如果投票是[A, B, C], 那么最后统计到[C, 1]也不能说明C的票超过半数,所以还要再遍历一次

遍历得到A的数量为3,超过半数,符合条件

那么,对于1/3:在任何数组中,出现次数大于该数组长度1/3的值最多只有2

对于1/3,则需要选择两个可能的候选人

推广到1/(m+1): 在任何数组中,出现次数大于该数组长度1/(m+1)的值最多只有m

题解

class Solution {
    public List<Integer> majorityElement(int[] nums) {
        // 创建返回值
        List<Integer> res = new ArrayList<>();
        if (nums == null || nums.length == 0) return res;
        // 初始化两个候选人candidate,和他们的计票
        int cand1 = nums[0], count1 = 0;
        int cand2 = nums[0], count2 = 0;

        // 摩尔投票法,分为两个阶段:配对阶段和计数阶段
        // 配对阶段
        for (int num : nums) {
            // 投票
            if (cand1 == num) {
                count1++;
                continue;
            }
            if (cand2 == num) {
                count2++;
                continue;
            }

            // 第1个候选人配对
            if (count1 == 0) {
                cand1 = num;
                count1++;
                continue;
            }
            // 第2个候选人配对
            if (count2 == 0) {
                cand2 = num;
                count2++;
                continue;
            }

            count1--;
            count2--;
        }

        // 计数阶段
        // 找到了两个候选人之后,需要确定票数是否满足大于 N/3
        count1 = 0;
        count2 = 0;
        for (int num : nums) {
            if (cand1 == num) count1++;
            else if (cand2 == num) count2++;
        }

        if (count1 > nums.length / 3) res.add(cand1);
        if (count2 > nums.length / 3) res.add(cand2);

        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值