leetcode - [229]求众数Ⅱ|刷题打卡

197 阅读1分钟

1. 题目描述

[229] 求众数‖
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。

示例 1:
输入:[3,2,3]
输出:[3]
    
示例 2:
输入:nums = [1]
输出:[1]
    
示例 3:
输入:[1,1,1,3,3,2,2,2]
输出:[1,2]
    
提示:
1 <= nums.length <= 5 * 104
-109 <= nums[i] <= 109
    
Related Topics 数组

2. 思路分析

​ 这道题可以理解为 多数元素 的进阶,条件从 n/2 转变成了 n/3。

  1. 简单入手的思路,可以通过一样的排序,之后找到统计数大于 n/3 的数,然后返回。

  2. 参考 多数元素 的思路,采用摩尔投票法

    ​ 但是,从 多数元素的题目我们可以得知,摩尔投票法的效率更加高,因此,也尝试使用摩尔投票法的方法来解答。解析题目可以知道,返回的集合,最多有两个数字,我们用两个变量来表示最后留下来的两个数字,再取两个变量来分别表示前面两个数字出现的次数

    ​ 然后在遍历数组的过程中,如果出现不等于两个变量的值的情况,则对两个变量的统计数分别减去1。

    ​ 最后的结果有可能存在两个数字的出现次数都不超过 n/3 ,因此,还需要对两个数字出现的次数来进行判断,再得出最后的结果

3. AC代码

public class No229 {

    public List<Integer> majorityElement(int[] nums) {
//        return method1(nums);
        return method2(nums);
    }

    /**
     * 排序后比较
     * 执行耗时:3 ms,击败了37.38% 的Java用户
     * 内存消耗:42.6 MB,击败了15.00% 的Java用户
     */
    private List<Integer> method1(int[] nums) {
        List<Integer> re = new ArrayList<>(nums.length / 3);
        Arrays.sort(nums);

        int flag = nums.length / 3;
        int nowNum = nums[0];
        int nowNumCount = 0;

        for (int num : nums) {
            if (num == nowNum) {
                nowNumCount++;
            } else {
                if (nowNumCount > flag) {
                    re.add(nowNum);
                }
                nowNum = num;
                nowNumCount = 1;
            }
        }
        if (nowNumCount > flag) {
            re.add(nowNum);
        }

        return re;
    }

    /**
     * 摩尔投票法
     *
     * 执行耗时:2 ms,击败了97.06% 的Java用户
     * 内存消耗:42.1 MB,击败了71.02% 的Java用户
     * @param nums
     * @return
     */
    private List<Integer> method2(int[] nums) {
        int flag = nums.length / 3;
        // 返回的列表,最大只有2
        List<Integer> re = new ArrayList<>(2);
        // 初始化
        int[] numArr = new int[]{ nums[0], nums[0] };
        int[] numCountArr = new int[]{ 0, 0 };

        // 如果非候选数组的数字,则统计数组的计数全都-1,统计数如果存在为0的话,就替换到数组的数字
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == numArr[0]) {
                numCountArr[0]++;
            } else if (nums[i] == numArr[1]) {
                numCountArr[1]++;
            } else if (numCountArr[0] == 0) {
                numArr[0] = nums[i];
                numCountArr[0] = 1;
            } else if (numCountArr[1] == 0) {
                numArr[1] = nums[i];
                numCountArr[1] = 1;
            } else {
                --numCountArr[0];
                --numCountArr[1];
            }
        }

        // 归0重新计数统计
        numCountArr[0] = 0;
        numCountArr[1] = 0;
        // 无法确定候选人的票都大于 n/3 需要遍历确认
        for (int num : nums) {
            if(num== numArr[0]) {
                numCountArr[0]++;
            } else if(num== numArr[1]) {
                numCountArr[1]++;
            }
        }

        if(numCountArr[0] > flag) re.add(numArr[0]);
        if(numCountArr[1] > flag) re.add(numArr[1]);
        return re;
    }
}

4. 总结

​ 学习要学会举一反三,我们从 【169-多数元素】中学到了摩尔投票法,在遇到类似的问题的时候,是否可以变通的去使用,更有效率的解答问题。


​ 本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情