转载-Array-Majority Vote Alogrithm(最大投票算法)及其扩展

转载 2017年12月28日 17:27:02

出处:https://segmentfault.com/a/1190000004905350

Boyer-Moore:A Linear Time Majority Vote Alogrithm,这是最基础的最大投票算法。

原文中提到:decides which element of a sequence is in the majority, provided there is such an element.,但是讲的有一些含糊。我再补充一下:在一次投票中,如果某一种投票出现的数量大于(这里必须是大于而不能是等于,否则在某些特殊条件下会得到错误结果)总投票,我们就认为这种投票是我们要找的 Majority Element。

参考 Leetcode 上的这道题:169.Majority Element

Given an array of size n, find the Majority Element. The Majority Element is the element that appears more than ⌊ n/2times.

You may assume that the array is non-empty and the Majority Element always exist in the array.

算法的具体思路是:假设在给定长度为 n 的数组中,Majority Element 出现的次数是 k 次,那么非 Majority Element 的出现次数就为 n-k。如果我们能去掉这 n-k 个元素那么剩下的就全部是 Majority Element 了。

我们可以遍历数组,当碰到两个不一样的数字时,我们将这两个数字同时丢弃这两个数字中可能有一个为 Majority Element,也可能两个都不为Majority Element.因为k 大于 n/2,所以在最差情况下(每次移除不同数字时都包含一个Majority Element),我们仍然能够保证最后得到的数字是Majority Element.

在网上看到的很多资料中,对这一步的解释都是略微有些问题的。很多人简单的将这一步解释为:找到一个Majority Element,随后找到一个 非Majority Element,并将他们一并移除,这其实是错误的。我们在循环的时候,并没有办法判定当前的数字是否为 Majority Element,所以在移除的时候,我们可能是移除了一个 Majority Element 和一个 非Majority Element,也有可能移除的是两个非Majority Element。所以最后 count 的值是不确定的,但是它能够保证在最差情况下,剩余的仍然是 Majority Element。例如,[1,2,3,3,3] 和 [1,3,2,3,3] 这两个数组最后得到的 count 分别为 3 和 1,但是这并不影响答案的正确性。

这也是前面提到的Majority Element的数量必须大于n/2的原因.

很容易算出最后剩余的Majority Element个数最少为: n - ((n - k) + (n - k)) = 2k - n。

public class Solution {
    public int majorityElement(int[] nums) {
        int candidate = 0;
        for(int i = 0,count = 0; i < nums.length; i++){
            //问题一: if 的判定顺序有要求吗?如果有要求的话应该是怎么样的呢?
            if(count == 0){
                count++;
                candidate = nums[i];
            }else if(candidate != nums[i]){
                count--;
            }else{
                count++;
            }
        }
        return candidate;
    }
}

这个算法很经典,也很简单,毕竟不用自己想。

接下来,我们可以对这个算法做一些简单的扩展,我们当前定义的 Majority Element 的数量大于 n/2 的元素。

如果我们在投票只要满足投票数量超过 n/3 即认为它是最大投票,我们能不能求出这个值呢?

妈蛋,文章中这种问题就跟小说里主角跳崖会不会死一样,有标准答案的。
乔治啊啊马丁:?

最大投票资料片:熊猫人之谜 229. Majority Element II

Given an integer array of size n, find all elements that appear more than ⌊ n/3times. The algorithm should run in linear time and in O(1) space.

思路依然同 Majority Element 一样,不同的是我们需要两个 Majority Element 的候选者,同时需要两个 count 分别对候选者进行计数。

count 为 candidate 当前出现的次数。count == 0 说明当前 candidate 对应的候选者已经被移除,我们需要设定一个新的候选者。

public class Solution {
    public List<Integer> majorityElement(int[] nums) {
        //问题二:这里给 candidate0 candidate1 初始化值为 0,这会不会影响我们运行的结果?
        int candidate0 = 0,candidate1 = 0,count0 = 0, count1 = 0;
        for(int i = 0; i < nums.length; i++){
            if(candidate0 == nums[i]){
                //当前数字等于一号候选数字
                count0++;
            }else if(candidate1 == nums[i]){
                //当前数字等于二号候选数字
                count1++;
            }else if(count0 == 0){
                //当前数字不等于一号候选数字或二号候选数字
                //同时必须满足 count 等于 0,因为如果 count != 0,说明还有候选数字在等待与它一组的另外两个数字
                count0++;
                candidate0 = nums[i];
            }else if(count1 == 0){
                count1++;
                candidate1 = nums[i];
            }else{
                //只有 不满足以上所有条件我们才能对 count 进行减操作
                count0--;
                count1--;
            }
        }

        //**问题三:这里能够省略 distinct() 吗?为什么?**
        return Stream.of(candidate0, candidate1).distinct().filter(num -> {
            int count = 0;
            for(int i = 0; i < nums.length; i++){
                if(nums[i] == num){
                    count++;
                }
            }
            return count > nums.length / 3;
        }).collect(Collectors.toList());
    }
}

我们再梳理一遍思路:我们需要找到三个不同的数字,然后抛弃掉这三个数字:
首先要判断是否等于candidate,如果等于candidate那么对应的 candidate 必须加一等待其他的数字来消除它
当有一个 candidate 的 count 为 0 时,说明该 candidate 已经全部被消除,我们需要设定新的 candidate 数字。
当一个数字不等于两个 candidate,同时两个 candidate 的 count 都不为零。这意味着当前这个数字就是这两个 candidate 等待的第三个数字。于是这三个数字被移除,同时他们的 count 都要减一。

这个算法到这里就结束了,时间复杂度是线性的 O(n),空间复杂度是 O(1)。
接下来是问题解答时间:

问题一: if 的判定顺序有要求吗?如果有要求的话应该是怎么样的呢?

答案是有要求,细心的读者可能发现,在 Majority Element 中,我们对 count == 0 的判断在对 candidate == nums[i] 的判断之前,而在 Majority Element II 中则正好相反。

这是因为,count == 0 是用来判断对应 candidate 的当前存活量,在判断这一步之前,我们必须确保数组中当前数字不等于 两个 candidate中的任意一个。否则,我们可能会在 count0!=0 && count1==0 && nums[i]==candidate0 时错误的将 nums[i] 赋值给 candidate1。

问题二:这里给 candidate0 candidate1 初始化值为 0,这会不会影响我们运行的结果?

不会,因为 candidate0 只会在第一次循环中使用,如果 candidate0 == nums[0],count++不会引起任何问题。如果 candidate != nums[0] 那么我们此时 count==0 重新初始化 candidate0 == nums[0],同样不会有任何影响。

问题二扩充:如果我们初始化 int candidate0 = 0, candidate1 = 1 会不会影响我们的运行结果呢?

问题三:这里能够省略 distinct() 吗?为什么?

不能,尽管我们在循环中首先通过 if(candidate0 == nums[i]) 和 else if(candidate1 == nums[i]) 两个 if 判断,使得 candidate0 != candidate1 在绝大部分下成立,但是在一种极为特殊的情况下仍然可能会使得我们得到重复的数组。

试想当整个数组所有的数字都相等的时候,我们 candidate0 和 candidate1 这两个候选数字中,有一个数字将永远不会被重新赋值,也就是说,有一个数字将我们赋给的初值保持到了最后。

在我们的代码中,因为我们将两个候选数字都初始化 0,所以当数组 全为0 时会返回错误的结果。

这一点,我们可以通过将两个候选数字初始化为不同的数字来解决:int candidate0 = 0,candidate1 = 1,这样我们就可以移除掉 distinct() 了

洛谷 P2057 善意的投票

(网络流)割
  • SenyeLicone
  • SenyeLicone
  • 2016年11月26日 16:49
  • 325

[SHOI2007]BZOJ1934 Vote善意的投票-最小割

题目链接:传送门 题目大意:请自行参考原题 题解:我承认如果不告诉我这是个最小割我是想不到的QWQ 一个同学i的意见是x如果x=1就建边(S,i,1)否则建边(i,T,1)。 如果xy是朋友就建边(x...
  • Mys_C_K
  • Mys_C_K
  • 2017年05月12日 15:12
  • 164

bzoj1934【shoi2007】Vote善意的投票

最小割
  • AaronGZK
  • AaronGZK
  • 2015年12月26日 00:05
  • 1304

集成学习学习笔记(2)

Bagging通过集成学习笔记1中对Boosting算法的描述我们知道对于Boosting算法,其各个基学习器之间是强相关的,即下一个学习器的学习偏好受之前学习器的影响很大,因为之前的基学习器的学习情...
  • batuwuhanpei
  • batuwuhanpei
  • 2016年08月01日 00:44
  • 1819

TENSOR VOTING算法——续

主要参考: 《range data analysis by free-space modeling and tensor voting》 输入点云默认只包含位置信息,所以初始化编码时,默认为球张量~...
  • u010658879
  • u010658879
  • 2015年03月20日 13:50
  • 1282

[Shoi2007]Vote 善意的投票

题目描述幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉。对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意...
  • oi_Konnyaku
  • oi_Konnyaku
  • 2017年12月27日 16:40
  • 59

简易在线投票系统(php)——发布投票页面

发布页面是在用户登录的状态下才能进行的所以要先检测是否处在登录状态,确定后再允许发布投票 注意:一旦发布将不能修改! 用户输入的信息会以post的格式发布到后台。 ...
  • tianyao9hen
  • tianyao9hen
  • 2016年01月10日 21:39
  • 1503

多数投票算法

在一个数组中,元素个数为n(假设最多投票元素存在),输出元素出现次数大于n/2的数 算法思路:1、一个变量cand表示所求的元素,一个变量count统计个数,将count初始化为0.         ...
  • wuli2496
  • wuli2496
  • 2015年10月08日 22:51
  • 2825

机器学习技法总结(四)(aggregation,vote,bootstrap...)

研究的动机是:我们采用了不同的模型得到T个不同的g,那么我们是不是可以通过这些不同的g的融合得到更加出色的G呢?因此,便有了以上四种不同的方法;1)(select)直接选择最好的一个作为融合的结果;2...
  • LG1259156776
  • LG1259156776
  • 2015年07月09日 20:37
  • 1869

刷投票软件 --分析 -- 实现 ---源码

原由:一个妹子找到锅,让我帮她投票,好的,投了几票交叉,妹子又说可以清除cookie投票,让我陪她投一晚上。。。哥当时听到这话吓尿了。。。过了会儿她说你不是学软件的,来搞个刷票软件吧,明显不同意,我方...
  • qqYOHA
  • qqYOHA
  • 2014年01月07日 21:16
  • 651
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:转载-Array-Majority Vote Alogrithm(最大投票算法)及其扩展
举报原因:
原因补充:

(最多只允许输入30个字)