Moore’s Voting Algorithm

Moore’s Voting Algorithm

接着上一篇 LintCode majority number (主元素), 继续讨论Moore Voting Algorithm。

Moore’s Voting Algorithm该算法是找出重复元素的最佳的算法,其时间复杂度为 O(n) 而空间复杂度为 O(1)

Moore’s Voting Algorithm最初提出来是解决了:给定一个整型数组,找出主元素,它在数组中的出现次数严格大于数组元素个数的二分之一问题。
其该算法只有两个步骤:
1. 找出候选的主元素
2. 判断候选的主元素出现的次数是否大于数组元素个数的二分之一。

MooreVotingAlgo(a[], size)

    // 找出候选主元素
    Initialize index and count of majority element
     maj_index = 0, count = 1
    Loop for i = 1 to size – 1
        If a[maj_index] == a[i]
            count++
        Else
            count--;
        If count == 0
            maj_index = i;
            count = 1
    // 判断候选主元素出现的次数是否大于size/2       
    count = 0
    Loop for i = 1 to size - 1
        if a[i] == a[maj_index]
            ++count;
        if count > size/2 
            return a[maj_index]
    return -1;

Moore’s Voting Algorithm 的一般情况,给定一个大小为 n 的数组b,找出数组b中元素出现次数大于 n/k 次的元素。在数组b中出现次数大于 n/k 的元素至多只有 k1 个不同的元素。很容易证明该问题。当 k=2 时,刚好可以使用标准的Moore’s Voting Algorithm来解决。
现在来讨论,k=3时

主元素 II

给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的三分之一。
样例
给出数组[1,2,1,2,1,3,3] 返回 1
注意
数组中只有唯一的主元素
挑战
要求时间复杂度为O(n),空间复杂度为O(1)。

解决该问题存在很多的方法,可以参考主元素I的解法来求解该问题。现在主要介绍如何使用Moore’s Voting Algorithm来求解该问题。由上面的讨论可知,最多存在两个不相同的元素。因此,可以稍微的修改Moore’s Voting Algorithm即可得到答案。

例如:给定数组b[1, 1, 2, 3, 1, 1, 2, 4, 2, 6, 2], 求出现次数严格大于数组元素个数的三分之一的元素
因为最多只存在两个不同的元素,因此,另他们为x1, x2, 出现的次数为xc1, xc2;

第一步:找出候选主元素
初始化: x1 = x2 = xc1 = xc2 = 0;
i = 0; e = 1 —> xc1 = 0 —> x1 = 1, xc1 = 1;
i = 1; e = 1 —> x1 = e —>xc1 = 2;
i = 2; e = 2 —> xc2 = 0 –> x2 = 2, xc2 = 1;
i = 3; e = 3 —-> xc1 = 1, xc2 = 0;
i = 4; e = 1 —> xc1 = 2;
i = 5; e = 1 —-> xc1 = 3;
i = 6; e = 2 —> xc2 = 0 —> x2 = 2, xc2 = 1;
i = 7; e = 4 —> xc1 = 2, xc2 = 0;
i = 8; e = 2 –> xc2 = 0 —> x2 = 2, xc2 = 1;
i = 9; e = 6 –> xc1 = 1, xc2 = 0
i = 10; e = 2 –> xc2 = 0 –> x2 = 2, xc2 = 1;
结果: x1 = 2, xc1= 1, x2 = 2, xc2 = 1;

第二步:验证候选主元素:

其代码如下

public static ArrayList majorityNumber(List nums) {
        // write your code
        ArrayList res = new ArrayList<>();

        int x1=0, x2=0, xc1 = 0, xc2=0;

        //找出候选主元素
        for (int e : nums) {
            if (e == x1) xc1++;
            else if (e == x2) xc2++;
            else if (xc1 == 0) {
                x1 = e; xc1 = 1;
            } else if (xc2 == 0) {
                x2 = e; xc2 = 1;
            } else {
                --xc1; --xc2;
            }
        }

        // 验证候选主元素
        xc1 = xc2 = 0;
        for (int e : nums) {
            if (e == x1) ++xc1;
            else if (e == x2) ++xc2;
        }
        if (xc1 > nums.size()/3) res.add(x1);
        if (xc2 > nums.size()/3) res.add(x2);

        return res;
    }

注意:lintCode上题目的意思是只存在于一个这样的元素,因此需要稍微的修改一下代码

    /**
     * @param nums: A list of integers
     * @return: The majority number that occurs more than 1/3
     */
    public int majorityNumber(ArrayList nums) {
        // write your code
        int x1 = 0, x2 = 0, xc1 = 0, xc2 = 0;
        for (int e : nums) {
            if (e == x1) xc1++;
            else if (e == x2) xc2++;
            else if (xc1 == 0) {
                x1 = e; xc1 = 1;
            } else if (xc2 == 0) {
                x2 = e; xc2 = 1;
            } else {
                --xc1; --xc2;
            }
        }

        xc1 = xc2 = 0;
        for (int e : nums) {
            if (e == x1) xc1++;
            else if (e == x2) xc2++;
        }
        if (xc1 > nums.size()/3) return x1;
        else if (xc2 > nums.size()/3) return x2;
        return -1;
    }

基于上面的分析应该对Moore’s Voting Algorithm比较熟悉,求解下列问题在思路上应该已经没有什么问题了。

主元素 III

给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的1/k。
样例
给出数组 [3,1,2,3,2,3,3,4,4,4] ,和 k = 3,返回 3
注意
数组中只有唯一的主元素
挑战
要求时间复杂度为O(n),空间复杂度为O(k)

现只给出使用Map实现的代码,有兴趣的可以使用Moore’s Voting Algorithm实现该算法

    public int majorityNumber(ArrayList nums, int k) {
        // write your code
        Map res = new HashMap<>();

        for (Integer e : nums) {
            Integer count = res.get(e);
            count = (count == null ? 1 : count+1);
            if (count > nums.size()/k)
                return e;
            res.put(e, count);
        }
        return -1;
    }

你可能感兴趣的:(lintCode)