Moore’s Voting Algorithm

来源:互联网 发布:移动云商城 源码 编辑:程序博客网 时间:2024/06/06 02:21

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<Integer> majorityNumber(List<Integer> nums) {        // write your code        ArrayList<Integer> 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<Integer> 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<Integer> nums, int k) {        // write your code        Map<Integer, Integer> 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;    }
0 0