[LeetCode 229.] 求众数 II

LeetCode 229. 求众数 II

给定一个大小为 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 * 10^4
  • -10^9 <= nums[i] <= 10^9

解题思路

这道题与那道【主元素】的题目非常相似,主元素指的是出现次数超过一半,这道题是要超过 1/3。
回顾之前主元素的做法,基本思路是说,先找出候选主元素,然后检验其是否符合要求。如何筛选主元素呢?从数组中删除一些元素,以减少候选数量即可。具体来讲,是每次从数组中删除两个不同元素,如果存在主元素,那么一定会被剩下。
这里的做法也类似,也是找候选众数,然后每次找到三个不同的数,就一起删除;如果存在众数,那么一定会被剩下,最后检验即可。

推广一下这个问题,如何从n个元素中找出出现次数超过 ⌊ n/m ⌋ 的元素呢?
操作仍然是每次从数组中挑选m个不同元素进行删除操作,如果有某个元素出现次数超过 ⌊ n/m ⌋ 次,那么采取一次删除m个不同元素的操作之后,最后一定能剩下。实际上这种方法有一个专门的名称,【摩尔投票法】。

参考代码

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        constexpr static int INVALID_VALUE = INT32_MIN;
        int m1 = INVALID_VALUE;
        int m2 = INVALID_VALUE;
        int cnt1 = 0;
        int cnt2 = 0;
        for (int x : nums) {
            if (x == m1) cnt1++;
            else if (x == m2) cnt2++;
            else {
                if (cnt1 <= 0) {
                    m1 = x; cnt1 = 1;
                } else if (cnt2 <= 0) {
                    m2 = x; cnt2 = 1;
                } else {
                    cnt1--;
                    cnt2--;
                }
            }
        }

        cnt1 = 0;
        cnt2 = 0;
        for (int x : nums) {
            if (x == m1) cnt1++;
            else if (x == m2) cnt2++;
        }
        vector<int> res;
        if (cnt1 > nums.size() / 3) res.push_back(m1);
        if (cnt2 > nums.size() / 3) res.push_back(m2);
        return res;
    }
};
上一篇:数字染色 gcd>1的子序列个数 容斥、莫比乌斯函数


下一篇:【外文翻译】使用Timer类去调度任务 ——java