leetcode上有一个算法题,求数组中出现一半以上的元素。
利用Moore’s voting algorithm可以方便地解决,算法介绍页面给出了解释。
实例
如下序列:
A A A C C B B C C C B C C
^
?:0
具体步骤见执行步骤
具体算法
我们将从上面显示的指针位置开始扫描序列。
当我们扫描时,我们利用两个参数:现在的候选元素,以及计数器。最初,目前的候选元素未知,且计数器为0.
当我们将指针向前移动一个元素e:
如果计数器为0,则将当前候选元素设为e,并将计数器设为1.
如果计数器不为0,则根据e是否为当前候选元素:
- 如果e==候选元素,则计数器加1;
- 如果e!=候选元素,则计数器减1;
当我们完成后,如果数组中只有一个超过半数的元素,则候选元素即为所求。
此算法的时间复杂度为O(n),空间复杂度为O(1)。
算法证明
试想,如果一个序列里面有k个majority,那么就有n-k个non-majority。不妨将non-majority当作一个整体,变成同一数(并不会影响程序的正确性),那么此时序列里面就变成了两种元素。
不失一般性,不妨令第一个元素为majority(此时恰好为non-majority的元素)。那么count最多到n-k。再然后就一定是majority的元素,那么最多需要n-k个,count就会变成0,此时总共经历了2n-2k,还剩余2k-n个元素,因为k大于n/2,所以,剩余元素个数为正数,而且全为majority。
这里用了两个假设:第一个是将所有的non-majority作为一个整体,第二个相当于是做了一个排序。
代码
leetcode169题的具体应用
class Solution {
public int majorityElement(int[] nums) {
int cand = nums[0];
int count = 1;
for(int i = 1; i<nums.length; i++){
if(count == 0)
cand = nums[i];
if (cand == nums[i])
count++;
else
count--;
}
return cand;
}
}