求多数元素——采用摩尔投票算法

博客探讨了在数组中寻找多数元素的问题,解释了传统的flag标记法为何在此问题上行不通,并详细介绍了使用摩尔投票法的解决方案。这种方法通过模拟混战,消除非多数元素,最终找到出现次数超过数组长度一半的元素。
摘要由CSDN通过智能技术生成

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

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

示例 1:

输入:[3,2,3]
输出:3
示例 2:

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


其实我一开始想到的不是这个方法,而是我常用的flag标记法

即将该数组元素(记作arr数组)作为flag数组的下标,每次碰到一个相同的值(比如:arr[1] == arr[2]),那他们作为flag的下标就会指向相同的一个flag数组的地址空间,这样,在所有都标记完了以后,flag[arr[1]]) == flag[arr[2]] == 该值出现的次数。flag数组初始化为0)最后,我们只需要再比较flag数组元素中值最大的那个flag元素的下标(即arr众数元素那个值)即可。

代码如下:

int majorityElement(int* nums, int numsSize) {
    int flag[1000] = { 0 };
    int n = numsSize / 2;
    int i = 0;
    int m = 0;

    for (i = 0; i < numsSize; i++)
    {
        flag[nums[i]] ++;
        if (flag[nums[i]] > n)
        {
            return nums[i];
        }
    }
    return 0;
}

但是,在这道题行不通

为什么呢?

因为arr数组中的元素可能包含负数,而负数不能作为程序的下标!


那我们只有换一种更加巧妙的方法——摩尔投票法

先看代码


int majorityElement(int* nums, int numsSize){
    int cut = 0;
    int res = 0 ;
    for(int i = 0; i < numsSize; i++)
    {
        if(!cut)
        {
            res = nums[i];
            cut++;
        }
        else 
        (res == nums[i])? cut++ : cut--;
    }
    return res;
}

 什么意思?

就是说,我们把他想象成一场世界大战。相同的元素代表同一个国家的一个士兵。

然后我们的世界大战打法是:混战,即没有特定的攻击对象,并且每个士兵的战斗力都是相同的,也就是说,加入A国有4个士兵,B国有1个士兵,C国有2个士兵,那么就算BC两国联合,A国最后都会剩下一个士兵,传承文明的种子继而称霸世界,于是我们可以发现,只要有一个国家,士兵数占据了全球士兵的一半以上,那这个国家就必然是最后的赢家(如果正好是全球士兵的一半,那么地球上就无人生还,全部都同归于尽了,但是如果没有这么一个国家,能达到全球士兵一半以上,那这最后的结果还不是很确定,当然,这道题给我们限制了多数元素的概念,即在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素,所以我们不用考虑

所以,我们的想法就是,从数组第一个元素写起,把他作为计数的标准(即先假想他是胜利国,记作cut),那么如果后面出现了相同元素(即士兵+1),就cut++,如果出现的是不同元素,就cut--(相当于死了一个士兵),如果cut变为了0(假如是在arr[5]处,cut变为了0),那么我们就换一个计数的标准(即arr[6],随即cut++,保证这个新的假想胜利国一开始就有这一个士兵了),随后一直做下去,直到这场混战结束,剩下的士兵,要么是一个,要么是多个,但是他们都是同一个国家的(题目上说让我们假设数组是非空的,并且给定的数组总是存在多数元素。)。最后我们返回这个值就行了。


int majorityElement(int* nums, int numsSize){
    int cut = 0;
    int res = 0 ;
    for(int i = 0; i < numsSize; i++)
    {
        if(!cut)
        {
            res = nums[i];
            cut++;
        }
        else 
        (res == nums[i])? cut++ : cut--;
    }
    return res;
}

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值