算法 - 摩尔投票算法

Boyer-Moore majority vote algorithm (摩尔投票算法)

典型案例:

(1) 找出大于n/2的元素,leetcode: https://leetcode.com/problems/majority-element/ 

class Solution {
    public int majorityElement(int[] nums) {
        int count = 0;
        int cur = 0;
        for(int i = 0; i < nums.length; ++i){
            if(count == 0){
                cur = nums[i];
                count++;
            }else{
                if(nums[i] == cur){
                    count++;
                }else{
                    count--;
                }
            }
        }
        return cur;
    }
}

(2) 找出大于n/3的元素, letcode: https://leetcode.com/problems/majority-element-ii/

/*
    思路:摩尔投票升级版,超过n/3的数最多只能有两个;
    先选出两个候选人A,B,遍历数组,如果投A(等于A),则A的票数++;如果投B,B的票数++;
    如果A,B都不投(即与A,B都不相等),那么检查此时是否AB中候选人的票数是否为0,如果为0,则成为新的候选人;
    如果A,B两个人的票数都不为0,那么A,B两个候选人的票数均--;
    遍历结束后选出两个候选人,但是这两个候选人是否满足>n/3,还需要再遍历一遍数组,找出两个候选人的具体票数
     */
    public List<Integer> majorityElement(int[] nums) {
        if (nums==null||nums.length==0){
            return null;
        }

        //初始化,定义两个候选人以及对应的票数
        int candidateA=nums[0];
        int candidateB=nums[0];
        int countA=0;
        int countB=0;

        // 遍历数组
        for (int num:nums){
            if (num==candidateA){ //投A
                countA++;
                continue;
            }

            if (num==candidateB){// 投B
                countB++;
                continue;
            }
            //此时A,B都不投,检查是否有票数为0情况,如果为0,则更新候选人
            if (countA==0){
                candidateA=num;
                countA++;
                continue;
            }

            if (countB==0){
                candidateB=num;
                countB++;
                continue;
            }

            //此时两个候选人的票数都大于1,且当前选名不投AB,那么A,B对应的票数都要--;
            countA--;
            countB--;
        }

        // 上一轮遍历找出了两个候选人,但是这两个候选人是否均满足票数大于N/3仍然没法确定,需要重新遍历,确定票数
        countA=0;
        countB=0;

        for (int num:nums){
            if (num==candidateA){
                countA++;
            }else if (num==candidateB){
                countB++;
            }
        }

        List<Integer> resultList=new ArrayList<>();

        if (countA>nums.length/3){
            resultList.add(candidateA);
        }

        if (countB>nums.length/3){
            resultList.add(candidateB);
        }

        return resultList;
    }

Boyer-Moore majority vote algorithm(摩尔投票算法)是一种在线性时间O(n)和空间复杂度的情况下,在一个元素序列中查找包含最多的元素。它是以Robert S.Boyer和J Strother Moore命名的,1981年发明的,是一种典型的流算法(streaming algorithm)。

在它最简单的形式就是,查找最多的元素,也就是在输入中重复出现超过一半以上(n/2)的元素。如果序列中没有最多的元素,算法不能检测到正确结果,将输出其中的一个元素之一。

当元素重复的次数比较小的时候,对于流算法不能在小于线性空间的情况下查找频率最高的元素。

假设这个数组中共有n个元素,我们可以把数值不同的元素看做不同的群体成员(一个数字代表一个群体)。那么我们现在要根据每个群在这个名单中各自的人数,使得在名单中出现人数最多的那个管理群。我们就先从数组的第一个元素开始,假定它代表的群体的人数是最多的,那么根据数组中出现次数超过一半的数只有一个的特质,如果我们设置一个计数器,在遍历时遇到不同于这个群体的人时就将计数器-1,遇到同个群体的人时就+1,只要在计数器归0时就重新假定当前元素代表的群体为人数最多的群体再继续遍历(此时数据被分为两段,前一段数据中被计数的元素数和numbers except it 数量是相等的,而后面的data中又满足词频最高的数大于总数一半的情形,有点分治策略的思想),那么到了最后,计数器记录的那个群体必定是人最多的那个群体。这里就使得元素排序是不会造成任何影响的,只关心元素的个数所带来的对于计数器+1或-1的影响。

算法实现:

法在局部变量中定义一个序列元素(m)和一个计数器(i),初始化的情况下计数器为0. 算法依次扫描序列中的元素,当处理元素x的时候,如果计数器为0,那么将x赋值给m,然后将计数器(i)设置为1,如果计数器不为0,那么将序列元素m和x比较,如果相等,那么计数器加1,如果不等,那么计数器减1。处理之后,最后存储的序列元素(m),就是这个序列中最多的元素。

典型的案例

(1)找出大于n/2的元素

(2)找出大于n/3的元素把两个数转化为一个数的思想,两个大于n/3的肯定大于一半
---------------------
作者:码农张学友
来源:CSDN
原文:https://blog.csdn.net/dpengwang/article/details/81710259
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自www.cnblogs.com/frankcui/p/10474223.html