【算法设计与分析】Majority Voting Algorithm-多数投票算法

问题:

有一个数组,里面是一些重复的数字。问是否存在一个数,这个数出现的次数超过了数组大小的一半?如果存在的话,这个数是多少?

例如对于数组[1,1,3,1,3,1,2],数字1的出现的次数超过了数组的一半;
而对于数组[6,6,6,7,7,7],没有数字超过数组的一半(数字6和7都出现了3次,出现的次数等于数组的一半,而没有超过数组的一半)

如果题目要求的是数字出现的次数大于等于数组的一半,那多数投票算法就失效了,只能用其他方法来实现。


解决方式:

对于这个问题,最佳的算法是多数投票算法,也叫作Boyer-Moore algorithm。
对这个问题,最大投票算法的时间复杂度是O(n)(总共遍历两次数组),空间复杂度是O(1)(总共维护两个变量)

算法的思想是,如果一个数存在超过数组的一半,则这个数和其他数相互抵消,最终还是会有自己的同党剩下来。
例如有一些人来投票,投的票选项分别是[1,3,2,1,1].
第一个人投1号,第二个人投3号,两个选票不同,相互抵消;
第三个人投2号,第四个人投1号,两个选票不同,相互抵消;
最后剩下一个1号投票,1号也是超过半数的投票号。

再看一个例子:[1,1,3,4,2]
第1、2个人的投票将选项1的票数累加到2;
第3、4个人的投票不是1,所以抵消选项1的票数到0;
最后一个人的投票是2.
但是很明显,2号不是多数的票号。所以我们需要再遍历一次数组来判断2号票是不是多数票。这个就是多数投票算法的思想


JAVA实现:

public int majorityVote(int nums[]) {
	int candidate=0,count=0;
	for(Integer num : nums) {
		if(num==candidate) {
			count++;
		}else if(count==0) {
			candidate=num;
			count=1;
		}else {
			count--;
		}
	}
	
	count=0;
	for(Integer num : nums)
		if(num==candidate)	count++;
	if(count>Math.ceil(nums.length/2))	return candidate; 
	return -1;    // 表示没有超过半数的票
}

传进函数的参数nums数组表示选票的票号,candidate表示可能的多数票号,初始值就设为0,count可以粗略理解为多数票号超过了其他票号的票数有多少。


拓展:

leetcode 229中求的就是超过三分之一的选票。

可以轻易想到,超过数组三分之一长度的数最多有两个,不可能有三个。
例如[1,1,1,2,2,2,3,3,3]就不存在超过数组三分之一长度的数字
而数组[1,1,1,2,2,2,3,3]存在两个超过数组三分之一长度的数字1、2

做法类似.

你可能感兴趣的:(算法设计与分析)