算法题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字(数组非空,一定存在这个数字)。
摩尔投票法算法的本质思想就是:抵消,抵消,抵消,到不能再抵消为止。
首先,我们先来了解一下是如何抵消的,抵消就是让数组中任意两个不同的元素进行抵消,一直抵消到最后剩下的就是出现次数唱过数组长度一半的数字了;具体的我们可以举一个例子来说明一下,给定的数组为{ 1, 2, 3, 2, 2, 2, 5, 4, 2 },具体抵消的过程为:
- 先声明一个数组array,用来存放当前无法抵消的数字;
- 遍历题目中给定的数组;第一个元素为 1,此时数组array为空,里面没有元素能够与 1 相互抵消,所以将 1 存入到数组中;
- 第二个元素为 2,此时数组array中存在一个 1 可以与 2 相互抵消,抵消之后数组array又变为空;
- 后面两个元素 3 和 2,也可相互抵消;遍历到第7个元素 5 的时候数组array为{ 2,2 },这时元素 5 可以与数组array中的任意一个 2 相互抵消,这里不用考虑与哪个 2 进行抵消;
- 继续遍历到最后,会发现数组array中仅剩一个 2,所以这个数字就是 2;
上面这个是摩尔投票法的具体流程,接下来我们就要考虑对其进行优化;可能大家会发现数组array的作用好像并不是很大,而且数组中存储的元素都只有一种,因为如果有与数组中元素不同的数字就会产生抵消,不会进行存储,因此我们在实际算法中可以将其替换;使用变量 x 表示数组array中存储的元素,变量votes存储的是其未被抵消的次数,具体思想和上面一样在此就不再过多赘述,直接上代码;
class Solution {
public int majorityElement(int[] nums) {
int x = 0, votes = 0;
for(int num : nums){
if(votes == 0)
x = num;
//如果遍历到的元素num与存储的元素x相等,则x存储的次数+1,否则就-1
num = num == x ? 1 : -1;
votes += num;
}
return x;
}
}
到这里这个算法已经全部分享完毕,但是一定会有同学存在这种情况,这个算法的思路也都明白了,自己也会写了,但是好像对不太理解为什么这样就可以保证最后留下的就是出现的次数超过数组长度一半的那个元素?
这里我再举一个例子,玩一个诸侯争霸类的游戏,你放的人口超过了所有总人数的一半,而且保证每次打仗都时一换一的(你方死一个人一定会杀死一个敌人),最后还有人或者的国家胜利;这个时候怎么办 ?对,就是直接选择大混战,所有的管家出来一起打,哪怕是其他国家联合打你一个,那么最后生存的也一定是你,因为你的人口超过了所有总人口的一半,即他们所有国家人加起来也没你的国家人多;如果他们之间也相互攻击,那岂不是更好了,所以只要你的国家不发生内斗,最后赢的一定是你。