169.多数元素

169.多数元素

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

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

示例 1:

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

示例 2:

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

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

首先,拿到题目抓重点,他说多数元素出现次数大于一半,说明什么??说明它是王者,即便它一对一和其他所有值单打最后都能留一个站在场上。

方法一:

那么看到“在数组中出现次数 大于 ⌊ n/2 ⌋ ”这句话,在我们脑子里第一印象一定是这样的:[(()^*********************#¥@!……&],对不对?那么就会想到让一样的排排站,这样就不得不想到排序,既然它数量过半,不论它多大,这一坨一样的数字排好序后都会在中间出现对不对,最次:[1,1,1,1,1,1,2,3,4,5,6],刚好多一个,所以我们可以排完序后取中间值,这个数一定是多数元素。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int n=nums.size();//数组元素个数
        std::sort(nums.begin(), nums.end());//排序
        if(n%2==0)//偶数个元素,取下标等于n/2的值
            return nums[n/2];
        else//奇数个元素,取下标等于(n-1)/2的值
            return nums[(n-1)/2];    
    }
};

关于就判断这里,要是没看懂,举个例子nums1=[1,1,1,1,1,1,2,3,4,5,6],n=11,奇数个元素,加粗元素位置一定是多数元素,他的下标是5=(n-1)/2=(11-1)/2;nums2=[1,1,1,1,1,1,1,2,3,4,5,6],n=12,偶数个元素,加粗元素位置一定是多数元素,他的下标是6=n/2=12/2,记住不会有nums3=[1,1,1,1,1,2,3,4,5,6]这种情况,因为不符合题目要求“在数组中出现次数 大于 ⌊ n/2 ⌋

方法一用了sort有个缺陷,我们只是简单的调了这个方法感觉很便利,但是计算机要累死了,那可是全排啊,费老大劲了。

那么方法二来了,我上边提到一句话“它一对一和其他所有值单打最后都能留一个站在场上”,这便衍生出一个进阶方法,那我们就让它和所有元素打一架吧,谁留到最后谁就是王者。

举个例子:

战场一:nums1=[1,1,1,1,1,1,2,3,4,5,6],我们让1和其他元素打架,由于它自带主角光环,天生能量多,所以,1🤺2,1🤺3,1🤺4,1🤺5,1🤺6过后还剩一个1在战场,那么毋庸置疑1是最多的。
现在我们来到第二战场:nums2=[1,1,2,1,3,1,1,4,5,6,1],从头开始遍历,两个1,遇到一个2,1🤺2战死一个1,此时剩下一个1了,向后走又遇到了1,此时剩下两个1,遇到3后1🤺3战死一个,还剩一个1,接着又是俩1,目前场上仨1,经过1🤺4,1🤺5,1🤺6后没有1了,但是最后一个数是1,所以最终留在场上的还是1;
现在看第三战场:nums3=[2,1,3,1,1,4,5,6,1,1,1],假设此时我们不知道谁会是冠军,开始遍历,上来一个2,不管了,立2为大将军(假设2是多数元素),然后2🤺1,大将军没了(此时不能说明2不是大将军,万一后边还有2的千军万马呢),大将军难道是后边的3?假装是吧,然后3🤺1死了,在看nums[4]与nums[5],他俩也不一样,碰死,然后是5和6也碰死,到此时为止前边碰死的元素(2,1,3,4,5,6)都没援军,那么接下来好日子来了,1的援军到了,最后留在场上的1是最多的,1胜了。

提问提问:为什么战场二只剩一个1,战场三剩下三个???
:战场二其实是最坏情况,就是每一个少数元素都是用一个1抵消的,那么之能剩下一个,而战场三有不同元素的内耗,比如5🤺6这种情况,就不用消耗1了,但凡5或者6是多数元素,到后边也会和1抵消的,从而留下5或6。
简单查了下这个思想叫候选人算法,实际上场景更复杂,有时间自己看看吧,别问我,我已经蒙了!!!

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        //候选人法
        int count=1,candidate=nums[0];//candidate就是多数元素,初始假设就是第一个元素,count就是它出现的次数
        for(int i=1;i!=nums.size();i++)
        {
            if(nums[i]==candidate)//遇到一次就++
                count++;
            if(nums[i]!=candidate)//碰死一次--
                count--;
            if(count<0)//数量小于0,换人
            {
                candidate=nums[i];
                count=1;//换人初始为1,毕竟人家还没跟人打仗呢,数量1
            }
        }
        return candidate;
    }
};

关于下边这块,新的候选人为什么是nums[i],而不是nums[i+1]?

if(count<0)//数量小于等于0,换人
	  {
	      candidate=nums[i];
	      count=1;//换人初始为1,毕竟人家还没跟人打仗呢,数量1
	  }

有两点原因:

1.i+1容易数组越界,因为i的范围最大值是数组末尾,i+1是越界的;
2.用nums=[2,2,1,1,1,2,2]举例子,初始候选人是2,当经历两个2🤺1后,2的个数为0,我们可以继续把2假设成候选人,但是又遇到一个1此时i=4,2的个数=-1,彻底败了,实际上此时1的个数已经比2多一个了,我们可以认定候选人为nums2[4]=1,也就是nums2[i]。

小彩蛋:上述代码

if(count<0)

也可以写成

if(count<=0)

你猜为啥???因为大将军无所畏惧

你,学废了吗???

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值