摩尔投票算法
现在有一组数,某一个数字a重复的次数超过了总数的一半,找出这个数字
对于这种情况,可以采用摩尔投票算法
思路就是:既然它出现的次数大于n/2 ,那我每次拿出两个不相等的数,直到拿完或者剩下的数字都一样,
最坏的情况就是每次拿出的数字都包含a,即使这样,最后数组里的数字仍然都是a
可以这样证明,比如有x个非a数字,有y个a
x+y=n;y>n/2 => y>x => y-x>0
可以这样去实现它:
就假设第一个数字是主要元素,然后开始遍历这个数组
遇到相同的我就cnt++ ,遇到不同的我就cnt --
每当cnt等于0,我就又回到了最开始的情况,那么怎么保证剩下的数组里的a仍然超过一半呢
示意图是这样的: [A0.... Z0,A1...Z1], 刚好走到A1的时候cnt=0
只要保证A0-Z0段a的个数没有超过一半,就可以保证A1-Z1段a的个数仍然超过一半
因为 y0+y1=y; num0+num1 =num ;2*y>num; => 2*y0+2*y1>num0+num1 => 2*y1>num1+(num0-2*y0)
所以当A0-Z0段a的个数小于等于该段总数一半的时候,A1-Z1段a的个数就是大于该段总数一半的
实质上A0-Z0段a的个数就是小于该段总数一半,因为倘若超过该段一半,cnt一定是个正数,不会为零
那么就又回到了原来的情况,周而复始即可
当遍历完成,如果cnt大于0,应该就意味着存在主要的数字,但是可能刚好上面说的A2就是最后一个数字,那么此时cnt也为1
所以稳妥起见,还是再遍历一遍,统计下该数字出现的次数
写个程序测试一下:
#include<stdio.h> int getMajor(int * nums,int num_size) { int major, cnt = 0; for (int i = 0; i < num_size;i++) { if (cnt == 0) { major = nums[i]; cnt += 1; } else cnt += ((major == nums[i]) ? 1 : -1); } int cnt2 = 0; for (int i = 0; i < num_size; i++) { if (nums[i] == major) cnt2++; if ((cnt2 * 2) > num_size) return major; } return -1; } int main() { int arr[] = { 1,1,1,3,5 }; printf("%d", getMajor(arr, 5)); return 0; }