【Lintcode】46. Majority Element

题目地址:

https://www.lintcode.com/problem/majority-element/description

给定一个数组,其中有一个数字出现的次数超过数组长度的一半。求出它。

可以用经典的摩尔投票算法,也就是Boyer-Moore Voting Algorithm。思路是这样的,从左向右扫描数组,同时维护一个变量count和另一个变量res储存最终答案。遍历到第一个数时, r e s res 初始化为第一个数,再将count加 1 1 ;此后,只要遇到等于res的数,就计count加一(相当于对其投票),如果遇到不同的数,就将count减一,如果count减到了 0 0 ,再遇到不同的数的时候,就将res改为那个新数,然后count加一,重新开始投票。扫描完数组后res存储的就是最终答案。代码如下:

import java.util.List;

public class Solution {
    /*
     * @param nums: a list of integers
     * @return: find a  majority number
     */
    public int majorityNumber(List<Integer> nums) {
        // write your code here
        int res = 0, count = 0;
        for (int i = 0; i < nums.size(); i++) {
        	// 如果计数为0,就选取新候选数并开始投票
            if (count == 0) {
                res = nums.get(i);
                count++;
            } else {
            	// 如果遇到相等的数则投票+1,否则投票-1
            	count += nums.get(i) == res ? 1 : -1;
            }
        }
        
        return res;
    }
}

时间复杂度 O ( n ) O(n) ,空间 O ( 1 ) O(1)

算法正确性证明:
构造一个数对序列,假设遍历到某数时 b b ,当前res为 a a ,如果 b a b\ne a ,那么就写下一个数对 ( a , b ) (a,b) ,也就是说每当count减少时,就写下一个数对,这个数对数字次序可以交换。如果count增加的时候则不写。如此一来,当整个数组遍历完成之后,就可以写下不超过 n / 2 n/2 个数对,其中 n n 为数组长度。

首先证明,如果将所有数对里的数都从数组里删掉,那么数组剩下的数一定都相等。假如不然,那么存在两个数 x y x\ne y 使得这两个数不属于任何数对,不妨设 x x 的位置在 y y 左边,那么当遍历到 x x 的时候,res里的数必然是 x x ,而在遍历到 y y 时,res里的数必然是 y y ,因为只有这样 x x y y 才不会出现在任何数对里;然而这是不可能发生的,因为在遍历到 y y 之前, x x 对应的count必然已经清到 0 0 了,所以 x x 必然属于某个数对。所以遍历完后不在数对里的数必然都相等。

接下来证明这些数就是出现次数大于一半的数 a a 。由于数对的数量是小于等于 n / 2 n/2 的,所以出现在数对里的 a a 的个数必然小于等于 n / 2 n/2 ,而 a a 出现的总次数是大于 n / 2 n/2 的,所以 a a 一定会最后剩下,也就是res里会存储 a a 。证毕。

发布了388 篇原创文章 · 获赞 0 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/105378355