LeetCode-169.多数元素+LeetCode-229.求众数II 摩尔投票解决众数问题

摩尔投票算法可以快速的计算出一个数组中的“大多数”,大多数即数组的众数,是数组中出现次数超过1/2的数字。该算法有线性时间复杂度和常数空间复杂度。当我们采用经过变形的摩尔投票算法,“大多数”的定义可以变为超过1/3、…、1/n的数字。

原版摩尔投票-求超过一半的数字

**前提:**给定数组非空且总是存在多数元素

定义一个记录候选数字的变量和一个记录候选数字出现次数的变量;然后遍历数组,根据“同加、异减”的原则,当遍历到的数字和候选数字相同,记录次数的变量+1,相当于票数+1,否则-1,相当于票数-1,若记录次数的变量小于等于0,候选变量更新为当前遍历到的元素,记录次数的变量置为1;完成遍历后,候选数字就是超过1/2的数字——相当于经过投票选举,候选人脱颖而出,被保留到了最后

我们可以采用摩尔投票法解决LeetCode-169.多数元素

题解代码:

public class Solution {
    public static void main(String[] args)
    {
        int[] nums={3,2,3};
        Solution obj=new Solution();
        System.out.println(obj.majorityElement(nums));
    }
    //使用摩尔投票法
    public int majorityElement(int[] nums)
    {
        int m=nums[0]; //候选数字
        int n=0; //记录候选数字出现次数(得票数)
        for(int i=0;i<nums.length;i++)
        {
            if(nums[i]==m)
            {
                n++;
            }
            else
            {
                n--;
                if(n==0)
                {
                    m=nums[i];
                    n=1;
                }
            }
        }
        return m;
    }
}

时间复杂度:O(n)
空间复杂度:O(1)

变形版摩尔投票-求超过1/3的数字

对摩尔投票法进行变形修改后,可以用来求数组中出现次数超过1/3的数字,理论上还可以求超过1/4、1/5 … 1/n的数字,这里我们以1/3为例

首先,我们要知道,是一个数组中,出现次数超过1/3的数字不超过2个,原因请大家自行证明。因此我们需要定义两个记录候选数字的变量m1、m2和两个记录候选数字出现次数的变量n1、n2

然后遍历数组,根据“同加、异减”的原则,遍历到的数字nums[i]首先和m1比较,相同则n1加一,若与m1不相同则和m2比较,相同则n2加一;若与m1、m2都不相同时,如果n1==0,让m1=nums[i]、n1=1,若n1!=0且n2==0,让m2=nums[i]、n2=1;若n1和n2都不为0,则让n1、n2分别减一

数组遍历完成后,还要检查保留下来的候选数字m1、m2是不是真的出现次数超过1/3:再遍历一遍数组,统计m1、m2出现次数

我们可以采用变形的摩尔投票解决LeetCode-229.求众数II

题解代码:

import java.util.ArrayList;
import java.util.List;
public class Solution {
    public static void main(String[] args)
    {
        int[] nums={1,1,1,3,3,2,2,2};
        Solution obj=new Solution();
        System.out.println(obj.majorityElement(nums));
    }
    //使用摩尔投票的变形
    public List<Integer> majorityElement(int[] nums)
    {
        int m1=Integer.MAX_VALUE,m2=Integer.MAX_VALUE; //数组中超过数组长度n/3的元素最多有两个
        int n1=0,n2=0;
        for(int i=0;i<nums.length;i++)
        {
            if(nums[i]==m1)
            {
                n1++;
            }
            else if(nums[i]==m2)
            {
                n2++;
            }
            else if(n1==0)
            {
                m1=nums[i];
                n1=1;
            }
            else if(n2==0)
            {
                m2=nums[i];
                n2=1;
            }
            else
            {
                n1--;
                n2--;
            }
        }
        n1=0; n2=0;
        for(int i=0;i<nums.length;i++)
        {
            if(nums[i]==m1)
            {
                n1++;
            }
            else if(nums[i]==m2)
            {
                n2++;
            }
        }
        List<Integer> result=new ArrayList<>();
        if(n1>(nums.length/3))
        {
            result.add(m1);
        }
        if(n2>(nums.length/3))
        {
            result.add(m2);
        }
        return result;
    }
}

时间复杂度:O(n)
空间复杂度:O(1)

你可能感兴趣的:(LeetCode-169.多数元素+LeetCode-229.求众数II 摩尔投票解决众数问题)