跳转至

数学——众数

众数是一组数中出现频率最多的数,可以用unordered_map来统计从而求得答案,但是对于一个特殊的序列,众数的出现次数大于n/2,解决方法就会比较多了。

题面以LeetCode 169.Majority Element为背景:

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.

Example 1:

Input: [3,2,3]
Output: 3

Example 2:

Input: [2,2,1,1,1,2,2]
Output: 2

排序法

排序的方法类似于求中位数的方法,因为出现次数最多的元素的数量大于n/2,所以排序后下标为n/2的一定就是众数。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        std::ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout.tie(NULL);

        sort(nums.begin(), nums.end());
        int n = nums.size();
        return nums[n / 2];
    }
};

摩尔投票法

这种方法还是第一次遇到,但是有一个大前提就是众数的出现次数至少是n/2,叫做摩尔投票法(Moore Voting),核心思路是每次让两个不同的元素抵消掉,那么最后剩下的就是众数了,直观上比较好理解。在写算法的时候,可以不用真的删掉元素,而是用一个sign值来标记,如果是两个不同的元素,那么数值减1,当减到0的时候,让res为当前元素,标记sign增加1.

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        std::ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout.tie(NULL);

        int sign = 0;
        int res = 0;
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            if (sign == 0) {
                res = nums[i];
                ++sign;
            }
            else {
                if (nums[i] == res) ++sign;
                else --sign;
            }
        }

        return res;
    }
};

位运算法

位运算的方法思路比较新奇,因为考虑到最后的结果是一个int类型的数,所以转而去检验每一位的1的个数,如果1的个数超过了n/2,那么这一位一定是1。

在这里插入图片描述

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        std::ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout.tie(NULL);

        int res = 0;
        int n = nums.size();
        for (int i = 0; i < 32; ++i) {
            int one = 0, zero = 0;
            for (auto num : nums) {
                if (one > n / 2 || zero > n / 2) break;
                if (num & (1 << i)) ++one;
                else ++zero;
            }
            if (one > zero) res |= (1 << i);
        }

        return res;
    }
};