给定一个大小为 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;
}