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<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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值