数组中出现次数超过一半的数字

本文介绍四种高效算法解决数组中多数元素查找问题,包括使用map计数、排序遍历、排序中间值判断及Boyer-Moore投票算法。适用于面试备考及实际问题解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

方法一:

定义一个关联容器map,将元素依次塞入map中,对每个元素w依次检验出现的个数,w.first为元素值,w.second为对应元素个数,如果个数大于长度的一半,就返回

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        int len=numbers.size();
        map<int,size_t>result;           //size_t一般用来表示一种计数
        auto tmp=numbers.begin();
        for(;tmp<numbers.end();tmp++)    //end指向尾元素之后的位置,区间为[begin,end)
            result[*tmp]++;              //解引用迭代器,得到了元素
        for(auto &w : result)
        {
            if(w.second>len/2)
                return w.first;
        }
        return 0;
    }
};

方法二:

对所有的元素进行排序,将所有元素遍历一遍,计算每种元素的个数,若当前元素的个数大于前面的统计结果,将结果刷新

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        int len = numbers.size();
        sort(numbers.begin(), numbers.end()); //对元素进行排序

        int num = 0, resultnum = 0;           //num为计数器,resultnum为元素数最多的元素的个数
        int result = *numbers.begin();        //结果初始化为第一个元素

        auto tmp = numbers.begin();
        while (tmp < numbers.end() - 1)       //下面需要对tmp++,所以tmp最大指到倒数第二个元素
        {//比较当前元素与下一个元素是否相等,相等,将计数器加1,同时也实现了元素后移
            if (*tmp == *(++tmp))
                num++;
            else
            {
                if (num > resultnum)          //当前元素个数大于前面的的统计结果
                {
                    resultnum = num;          //刷新元素个数最大值
                    result = *(tmp-1);        //前面比较元素相等时,将tmp后移了一位,这里需要减1
                }
                num = 0;                     //重置计数器
            }
        }
        if (resultnum + 1 > len / 2)         //resultnum计算结果为对应元素个数减1
            return result;
        return 0;
    }
};

当然也可以用for循环代替while循环

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        int len = numbers.size();
        sort(numbers.begin(), numbers.end());    //对元素进行排序
        int num = 0, resultnum = 0;              //num为计数器,resultnum为元素数最多的元素的个数
        int result = *numbers.begin();           //结果初始化为第一个元素
                                                 //下面需要对tmp+1,所以tmp最大指到倒数第二个元素
        for(auto tmp = numbers.begin();tmp < numbers.end() - 1;tmp++)
        {//比较当前元素与下一个元素是否相等,相等,将计数器加1
            if (*tmp == *(tmp+1))
                num++;
            else
            {
                if (num > resultnum)            //当前元素个数大于前面的的统计结果
                {
                    resultnum = num;            //刷新元素个数最大值
                    result = *(tmp);
                }
                num = 0;
            }
        }
        if (resultnum + 1 > len / 2)            //resultnum计算结果为对应元素个数减1
            return result;
        return 0;
    }
};

对于vector的操作,不仅可以解引用迭代器来获取元素,也可以通过下表来获取元素,如vector类型的变量numbers,numbers[0]表示第一个元素,下标从0开始;
对所有元素进行排序,则相等的元素将会在相邻的位置。设置一个临时量等于每一种元素的第一个元素,循环统计这种元素的个数;若后面有数量更大的元素,刷新这个记录,统计出最大个数的元素,如果数量大于总长度的一般,返回这个元素

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        int len=numbers.size();
        if(len==0)
            return 0;
        sort(numbers.begin(),numbers.end());
        int num=0,resultnum=0;
        int result=numbers[0];
        int tmp=numbers[0];
        //若容器中只有一种元素,则不会出现下面循环中else,即不会更新result与resultnum
        if(numbers[0]==numbers[len-1])
            return numbers[0];
        for(int i=0;i<len;i++)
        {
            if(tmp==numbers[i])
                num++;
            else
            {
                if(num>resultnum)
                {
                    resultnum=num;
                    result=tmp;
                }
                num=1;
                tmp=numbers[i];
            }
        }
        if(resultnum>len/2)
            return result;
        return 0;
    }
};

方法三:

数组排序后,如果符合条件的数存在,则一定是数组中间那个数。(比如:1,2,2,2,3;或2,2,2,3,4;或2,3,4,4,4等等)

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        int len = numbers.size();
        if (len == 0) 
            return 0;
        sort(numbers.begin(),numbers.end());    //排序
        int count=0;
        int middle = numbers[len/2];           //取中间值,注意,中间值是第len/2+1个,但下标是len/2
        for (int i = 0; i < len; i++)
        {
            if (middle==numbers[i])
                count++;
        }
        if(count>len/2)
            return middle;
        return 0;
    }
};

时间复杂度分析:涉及到快排sort,时间复杂度为O(NlogN);

方法四:

采用用户“分形叶”思路(注意到目标数超过数组长度的一半,数组同时去掉两个不同的数字,到最后剩下的就是目标数),如果没有超过数组长度的一半的目标数,则剩下某一个,所以最后要统计剩下的这个数的个数,大于数组长度一半,则返回该数,不大于,返回0。

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        int len = numbers.size();
        if (len == 0) 
            return 0;
        int count = 1;
        int tmp = numbers[0];
        for (int i = 1; i < len; i++)
        {
            if (count == 0)
            {
                tmp=numbers[i];
                count=1;
            }
            else if (tmp==numbers[i])
                count++;
            else
                count--;
        }
        int result=tmp;
        int num=0;
        for (int i = 0; i < len; i++)
            if(result==numbers[i])
                num++;
        if(num>len/2)
            return result;
        return 0;
    }
};

时间复杂度分析:O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值