(LeetCode C++)多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例1:

输入:nums = [3,2,3]
输出:3

示例2:

输入:nums = [2,2,1,1,1,2,2]
输出:2

提示:

n == nums.length
1 <= n <= 5 * 104
-109 <= nums[i] <= 109

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

Method 1:基于map/unordered_map遍历的方法

Code:

class Solution
{
public:
    int mejorityElement(vector<int> &nums)
    {
        // map基于红黑树实现,查找的时间复杂度O(n)
        // map<int,int> visited;
        // unordered_map基于哈希表实现,查找的时间复杂度较低O(1)
        unordered_map<int,int> visited;

        // 遍历数组
        for(int i=0;i<nums.size();i++)
        {
            // 记录当前数字出现的次数
            visited[nums[i]]++;

            // 如果当前数字出现的次数大于数组长度的一半
            if(visited[nums[i]]>nums.size()/2)
            {
                // 则该数字是多数元素
                return nums[i];
            }
        }

        // 如果没有多数元素,返回-1
        return -1;

    }
};

Method 2:基于排序的方法

Code:

class Solution
{
public:
    // 基于排序的方法
    // 多数元素的出现次数大于当前数组长度的一半
    // 因此排序后的数组中心位置必定是多数元素
    int majorityElement(vector<int> &nums)
    {

        // 需要#include<algorithm>
        // 对数组进行从小到大的排序
        sort(nums.begin(),nums.end());
        // 返回中位数
        return nums[nums.size()/2];

    }
};

Method 3:基于随机数的方法

Code 1:

class Solution
{
public:
    // 基于随机数的方法
    // 因为多数元素的出现次数大于当前数组长度的一半
    // 所以从数组中随机选一个数,这个数大概率就是我们要找的多数元素
    int majorityElement(vector<int> &nums)
    {
        // 在C/C++中,rand函数可以用来产生随机数,
        // 但是这不是真正意义上的随机数,是一个伪随机数.

        // 伪随机数是根据种子(seed)为基准以某个递推公式推算出来的一个系数,
        // 但这并不是真正的随机数.
        // 当计算机正常开机后,这个种子的值便固定下来.
        // 除非重新启动系统,否则这个种子的值并不会改变.

        // 因此,为了解决伪随机数的问题,C/C++提供了srand()函数,
        // 它的函数原型是 void srand(int a) ,可以用来改变这个种子的值.

        // time(nullptr)函数
        // 得到一个从1900年1月1日到现在的时间秒数,
        // 这样每一次运行程序的时间不同就可以保证产生不同的随机种子值,
        // 从而得到不同的随机数

        // 设置随机种子,确保每次得到不同的随机数
        srand(time(nullptr));

        // 直到返回多数元素后才停止循环
        while(true)
        {
            // 保存当前数组的长度
            int n=nums.size();
            // 统计随机数出现的次数
            int count=0;

            // 随机取出数组中的一个元素
            // C++中 rand()函数不需要参数,
            // 会返回一个从0到最大随机数的任意整数
            int random_integer=nums[rand()%n];

            // 遍历数组
            for(int nu:nums)
            {
                // 统计随机整数的出现次数
                if(nu==random_integer)
                {
                    count++;
                }
            }

            // 如果当前数字的出现次数大于数组长度的一半
            if(count>n/2)
            {
                // 则该数字是多数元素
                return random_integer;
            }
        }

    }
};

Code 2:

class Solution
{
public:
    // 基于随机数的方法
    // 因为多数元素的出现次数大于当前数组长度的一半
    // 所以从数组中随机选一个数,这个数大概率就是我们要找的多数元素
    int majorityElement(vector<int> &nums)
    {
        // 在C/C++中,rand函数可以用来产生随机数,
        // 但是这不是真正意义上的随机数,是一个伪随机数.

        // 伪随机数是根据种子(seed)为基准以某个递推公式推算出来的一个系数,
        // 但这并不是真正的随机数.
        // 当计算机正常开机后,这个种子的值便固定下来.
        // 除非重新启动系统,否则这个种子的值并不会改变.

        // 因此,为了解决伪随机数的问题,C/C++提供了srand()函数,
        // 它的函数原型是 void srand(int a) ,可以用来改变这个种子的值.

        // time(nullptr)函数
        // 得到一个从1900年1月1日到现在的时间秒数,
        // 这样每一次运行程序的时间不同就可以保证产生不同的随机种子值,
        // 从而得到不同的随机数

        // 设置随机种子,确保每次得到不同的随机数
        srand(time(nullptr));

        // 直到返回多数元素后才停止循环
        while(true)
        {
            // 保存当前数组的长度
            int n=nums.size();
            // 统计随机数出现的次数
            int count=0;

            // 随机取出数组中的一个元素
            // C++中 rand()函数不需要参数,
            // 会返回一个从0到最大随机数的任意整数
            int random_integer=nums[rand()%n];

            // 遍历数组
            for(int nu:nums)
            {
                // 统计随机整数的出现次数
                if(nu==random_integer)
                {
                    count++;
                }

                // 如果当前数字的出现次数大于数组长度的一半
                if(count>n/2)
                {
                    // 则该数字是多数元素
                    return random_integer;
                }
                
            }

        }

    }
};

Method 4:基于分治的方法

Code:

class Solution
{
public:
    // 基于分治的方法
    // 每一次都把一个大区间划分为两个子区间,并分别寻找两个子区间的多数元素,并递归进行
    // 其中,大区间的多数元素肯定是子区间的多数元素之一

    // 统计子区间元素n的个数
    int Element_count(vector<int> &nums,int n,int left,int right)
    {
        // 记录元素n的个数
        int count=0;
        // 循环遍历子区间
        for(int i=left;i<=right;i++)
        {
            // 统计元素n的个数
            if(nums[i]==n)
            {
                count++;
            }
        }
        // 返回元素n的个数
        return count;
    }

    // 递归的寻找子区间的多数元素
    int sub_majorityElement(vector<int> &nums,int left,int right)
    {
        // 如果左边位置等于右边位置
        if(left==right)
        {
            // 此时子区间长度为1
            // 返回子区间本身的唯一元素
            return nums[left];
        }
        // 区间的中点
        int middle=(left+right)/2;

        // 递归寻找左边子区间的多数元素
        int sub_left=sub_majorityElement(nums,left,middle);
        // 递归寻找右边子区间的多数元素
        int sub_right=sub_majorityElement(nums,middle+1,right);

        // 判断左边子区间的多数元素是否为大区间的多数元素
        if(Element_count(nums,sub_left,left,right)>(right-left+1)/2)
        {
            // 如果是,则返回
            return sub_left;
        }
        // 判断右边子区间的多数元素是否为大区间的多数元素
        if(Element_count(nums,sub_right,left,right)>(right-left+1)/2)
        {
            // 如果是,则返回
            return sub_right;
        }

        // 如果没有多数元素,返回-1
        return -1;
    }

    int majorityElement(vector<int> &nums)
    {
        return sub_majorityElement(nums,0,nums.size()-1);
    }
};

Method 5:Boyer - Moore 摩尔投票法

Code 1:

class Solution
{
public:
    // Boyer - Moore 摩尔投票法

    // 候选人是众数,所以得票数一定是最多的
    // 赞成票一定大于反对票,最终众数胜出

    // 可以理解为:每个数为一队,打群架.
    // 两个不是一队的人,势均力敌,双双倒下.
    // 因为众数队人多,所以最后获胜的一定是众数队

    int majorityElement(vector<int> &nums)
    {
        // 记录当前的数
        int mode=-1;
        // 当前数的个数
        int count=0;

        // 遍历整个数组
        for(int nu:nums)
        {
            // 如果相同
            if(nu==mode)
            {
                // 当前数的个数+1
                count++;
            }
            else
            {
                // 如果不同,当前数的个数-1
                count--;
                // 如果当前数被消耗殆尽
                if(count<0)
                {
                    // 则将下一个数设置为当前的数
                    // 并设置个数为1
                    count=1;
                    mode=nu;
                }
            }
        }
        // 返回多数元素
        return mode;
    }
};

Code 2:

class Solution
{
public:
    // Boyer - Moore 基于栈的摩尔投票法

    // 候选人是众数,所以得票数一定是最多的
    // 赞成票一定大于反对票,最终众数胜出

    // 可以理解为:每个数为一队,打群架.
    // 两个不是一队的人,势均力敌,双双倒下.
    // 因为众数队人多,所以最后获胜的一定是众数队

    int majorityElement(vector<int> &nums)
    {

        // 建立一个栈来存放可能是多数元素的节点
        stack<int> visited;

        // 遍历整个数组
        for(int nu:nums)
        {

            // 若栈为空或当前元素等于栈顶元素
            if(visited.empty()||nu==visited.top())
            {
                // 当前元素进栈
                visited.push(nu);
            }
            // 若当前元素不等于栈顶元素
            else if(nu!=visited.top())
            {
                // 栈顶元素出栈
                visited.pop();
            }
        }

        // 返回栈顶元素
        // 此时栈中只剩下多数元素
        return visited.top();

    }
};

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/majority-element

Reference:

C++ LeetCode 169 多数元素_Mr.禾的博客-CSDN博客

C++小笔记——srand(time(null))函数_Kadima°的博客-CSDN博客_c++srand(time(null))函数

C++中rand()函数的用法_抠脚老騷的博客-CSDN博客_c++ rand

c++ stack用法详解_斯文~的博客-CSDN博客_c++ stack

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Think@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值