摩尔投票 力扣229. 求众数 II 进阶篇

140 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

在这里插入图片描述

算法解释

	之前的解题报告里,我们已经使用了普通的一种解决方法,而进阶的解题方法要求O(n)的时间复杂度和O(1)的
空间复杂度,也就是说,必须线性方法就要解决问题,这时候我们也应该能发现,通用的解法已经行不通了,那么我
们要引入一个新算法——摩尔投票法
	摩尔投票法,顾名思义,就是解决投票选举类似的问题,我们先构思一个场景,如果有n个人在进行选举,大家
投票来选举最终的候选人,得票超过n/2的人即可获胜(假设一定会存在这样一个),一般来说,简单思路就是统计
最后票数然后得结果就好了,那如果说选举人都不喜欢数学,不想数学,喜欢简单粗暴的方法,而每个人投票人实力
相同,1V1谁也不占上风,都能同归于尽,大家不同阵营的打一架,俩俩抵消出局,那最后留下来的一定就是多数的
阵营,这就是简单的摩尔投票法。

算法变换

	而在这个题目当中,我们发现,情况又不一样了,这里不是求N/2,而是N/3,但其中的思想没有改变,那我们的
算法该如何进行一个变化使得摩尔投票法能重新适用呢?
	其实我们可以想象一个临界条件,N/2时,什么情况下会出现选不出来的情况?均票,而均票的一个极端就是2
个人,一人N/2,那么其实N/3时的极端均票情况也差不多,3个人,每人都是N/3,N/2情况选不出是因为俩俩抵消了
,那N/3情况呢?没错,就是三三抵消了!但这时有人会说,如果投票情况是{1,11,22,1},三三抵消那还剩下12,而2是不合要求的,这时候我们其实只要对这两个数字再遍历检验一下就OK了,而且不影响其O(N)的时间复杂
度,而空间复杂度上,我们需要的也就是新建几个变量,O(1)的空间复杂度,妥妥的!

代码

class Solution {
    public List<Integer> majorityElement(int[] nums) {
        List<Integer> ans = new ArrayList<>();
        int num1 = 0,num2 = 0,times1 = 0,times2 = 0;//各数字与计数器
        int length = nums.length;
        for(int i = 0;i < length;i++)
        {
            if(nums[i] == num1) times1 ++;
            else if(nums[i] == num2) times2 ++;
            else if(times1 == 0) {
                num1 = nums[i];
                times1 ++;
            }
            else if(times2 == 0){
                num2 = nums[i];
                times2 ++;
            } 
            else
            {
                times1 --;times2 --;
            }
        }
        if(times1 > 0)//最后验证一下即可
        {
            times1 = 0;
             for(int i = 0;i < length;i++)
                if(nums[i] == num1) times1 ++;
            if(times1 > length/3)
                ans.add(num1);
        }
        if(times2 > 0)
        {
            times2 = 0;
             for(int i = 0;i < length;i++)
                if(nums[i] == num2) times2 ++;
            if(times2 > length/3)
                ans.add(num2);
        }
        return ans;
    }
}