本题来源于Leetcode网,原题链接如下:
问题描述
给定一个大小为 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
题解:
通过这道题,可以认识和学习一个新算法——摩尔投票算法。
对于摩尔投票,顾名思义,其实就是这么一个场景:
台上有多位候选人,台下给他们投票,其中票数超过一半的则可成功当选。回到问题中就是,给一个集合,此集合中总存在多数元素,也就是某元素的个数超过整体元素个数的一半,让找出这个多数元素。
下面介绍这个算法的核心:互拼消耗
- 先说结论吧:若一个集合中存在多数元素,两个不同的元素为一对互拼消耗,那么互拼消耗的最后一定至少会剩下一个元素,此元素就为多数元素
- 举个简单例子:
设集合:{1,1,1,2,3}
那么可能有以下两种互拼方式:
(1)元素2与一个元素1互拼消耗,元素3与另一个元素1互拼消耗,最后剩下一个元素1,元素1是多数元素
(2)元素2与元素3互拼消耗,剩下三个元素1,因为相同,不进行互拼,同样得到元素1为多数元素 - 也可以这么理解,可能会更形象一些:
一场大战中,有多个阵营,那么在武器、装备、个人战斗能力等条件都相同之下,阵营与阵营间进行对拼,最后胜利的一定是那个人多的阵营(除非有二五仔哈哈),也就是阵营人数超过这场大战总人数的一半。
可以看出,互拼的方式与集合中元素的相对位置有一定的关系,集合中元素的不同排列形式可能会产生不同的互拼方式,但不会影响最终的互拼结果。
那么回到问题中,用代码该如何实现呢?
这里先呈上代码,根据代码结合具体场景说明可能会更形象一些:
int majorityElement(int* nums, int numsSize)
{
int candidate = 0;
int count = 0;
for(int i = 0; i < numsSize; i++)
{
if(0 == count)
{
candidate = nums[i];
}
if(candidate == nums[i])
{
count++;
}
else
{
count--;
}
}
return candidate;
}
那么,我们回到那场大战中,假设所有阵营的目的都是抢占一块高地,哪个阵营的人先到,就率先在高地上插旗,那么遍历数组的过程就可以看作每个阵营的士兵逐个进入高地的过程,如此一来就可以有如下几种情况:
1. 高地上没有人:
第一个到来的士兵插上自己阵营的旗帜(count++),那么candidate就是此时这个阵营的人,此时这个阵营就是这块高地的领主,count = 1代表此阵营当前现存兵力。
2. 高地上已经有人:
(1)新来的士兵与高地上的士兵属于同一阵营,则集合起来占领高地,领主不变,candidate 依然是当前这个士兵所属阵营,现存兵力 count 加一;
(2)新来的士兵与高地上的士兵不属于同一阵营,则双方展开厮杀,那么在前面所说装备、个人能力等条件都相同下,每次厮杀的结果都会是“一换一”,此时领主阵营的兵力减一,若某次厮杀结束后领主阵营的最后一名士兵恰好与另一阵营的士兵同归于尽,此时原来占据高地的领主阵营现存兵力虽为0,但由于还未有新的阵营的士兵到来,故领主还是原阵营,即candidate不变
3. 经历了 2 之后,高地上没有兵力,但存在原领主阵营的旗帜:
下一个士兵到来,发现前方阵营已经没有兵力,新士兵所属阵营就成了新的领主阵营,candidate 变成这个士兵所属阵营的旗帜,现存兵力 count ++。
就这样各方阵营一直厮杀以一敌一同归于尽的方式下去,直到少数阵营都死光,剩下几个必然属于多数阵营的,candidate 是多数阵营。
(注:此形象解释来源于此视频及评论:https://leetcode.cn/problems/majority-element/solutions/21733/javashi-pin-jiang-jie-xi-lie-majority-element-by-s/)
- 再举个例子来理解:
设集合{1,2,3,1,1}
一开始,1阵营士兵进入高地,此时领主就为1阵营;
接着,2阵营一名士兵进入高地,与1阵营的一名兵力厮杀,同归于尽后,高地上领主仍为1阵营;
然后,3阵营一名士兵进入高地,发现高地没有兵力,插上自己阵营的旗帜,成为领主;
再然后,1阵营士兵进入高地与3阵营一名兵力厮杀,同归于尽后,高地上领主仍为3阵营;
最后,1阵营一名士兵进入高地,发现高地没有兵力,插上自己阵营的旗帜,成为领主;1阵营就是多数阵营,即此集合中1为多数元素。
以上就是我对摩尔算法的理解和分享啦。
看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或看不懂的地方或有可优化的部分还恳请朋友们留个评论,多多指点,谢谢朋友们!🌹🌹🌹