zoukankan      html  css  js  c++  java
  • 【算法】摩尔投票

    【摩尔投票】

      问题: (majority element)若有一个数组L,长度为n,找出是否有一个数N,N的出现次数大于等于n/2。

      问题不算太难,一般可以通过遍历计数,或者排序找中位数的办法来解决。但是如果要求时间复杂度是O(n),空间复杂度是O(1),那么恐怕就没那么简单了。摩尔投票算法正好是这么一个O(n)和O(1)的算法。

      

      ●  描述

      声明m=0和cnt=0两个变量后面用。

      遍历数组,当cnt为0时将当前遍历到的元素赋值给m,然后cnt+=1。若cnt不为0,且遍历到的元素等于当前的m,那么cnt += 1,;若cnt不为0,但是遍历到的元素也不等于当前的m,那么cnt -= 1。最终遍历完成之后,变量m的值就是我们要找的那个majority element。

      

      为什么这个算法奏效?我们姑且从感性的角度来理解一下。既然是投票,那么就把这个数组YY成一个投票人的集合。这些投票人心中都有自己想要投的人,然后我们要找出的就是哪个候选人得票能过半的。因为我们无法做到同时听取所有人的想法,所以我们采取一种“淘汰制”选择。首先第一个人上台说明他想要推举的候选人比如说a。如果第二个人也是推举a的,那么可以认为a的人气是两人份的。第三人如果不是推举a的,那么他将减少a的一份人气。因为选举是要求最终得票过半,所以对于候选人a来说,每一个人不投票给他,就相当于他损失了一票。若第四人也不投a,则a的人气归零,和其他候选人重回起跑线,但此时站在候选台上的仍然是a。此时第五人若想就可以推举他想选的人b,把a给挤下来,b的人气为1。以此类推… 从大局上讲,如果a的支持者势力足够强大,那么无论a被打倒多少次,最终还是能够回到候选台上。这边势力强大的具体量化就是a的支持者至少达到n/2人。这样即使前一半人都支持a,后一半人都不支持a,最终a的人气归零,但是还是保证站在候选台上的是a。

      上面就是对投票算法的一个粗浅且感性的理解。

      ●  代码:

    def vote(a):
        m,cnt = 0,0
        for n in a:
            if cnt == 0:
                m = n
                cnt = 1
            elif n == m:
                cnt += 1
            else:
                cnt -= 1
        return m

      上述过程中并没有对投票者支持的人非常分散的情况作出判断。即无法完成选举的时候不会给出无法完成的错误,而是返回了接近数组末尾的某个“势力相对较强”的元素。如果需要对是否超过n/2做判断那么可以再去遍历依次数组,看到底m元素出现了几次,是否达到标准即可。

      ●  更复杂一点

      如果将问题换成,找出所有出现次数大于n/3次的元素呢。显然,这种元素最多只能有两个。所以我们可以使用投票算法,将有可能是符合要求的两个元素找出来,然后再看他们是否都超过了n/3来判断是否选择它们作为需要选出来的元素。

      具象到选举中来,那么可以认为现在要选的人是两个。而且这两个人竞选的位置是平级,不分先后的,所以热门候选人a和热门候选人b的支持者之间不构成直接竞争。因此,算法就变成了,第一人推荐a,a走上甲候选台。第二人推荐b,b走上乙候选台,而此时对a不构成影响所以a的人气不减。如果第三人推荐的是c,那么a和b的人气都要减一份,都归零了(显然不能只减一个人的人气,否则另一个人就可能会出现明明支持者很少,但是由于推举的顺序比较靠前所以当选的bug)。如果此时第四人支持的不是a或者b而是d,那么就可以从甲乙任意一个候选台中挤走一个。比如挤走a,之后d的人气是1,而另一个候选台上的b仍然是0人气。这么循环下去,由于a和b不互相竞争,所以通过这个算法得到的a和b是所有候选人中相对强势的两个。

      代码的实现也不复杂:

    def vote(a):
        m,n = 0,0
        cm,cn = 0,0
        for i in a:
            if cm == 0: m = i; cm += 1
            elif cn == 0: n = i; cn += 1
            elif i == m: cm += 1
            elif i == n: cn += 1
            else: cm -= 1; cn -= 1
        return m,n

      * 其实摩尔投票,主要是为了能够在O(n)的时间和O(1)的空间解决问题。如果没有这些限制,那么使用HashMap或者其他的一些什么方法则要比这种方法好理解得多多。

  • 相关阅读:
    Asp.net core 3.1+EF Core2.2.6+Oracle.EntityFrameworkCore2.1.19连接Oracle数据库
    外业数据采集平台(GPS+Android Studio+Arcgis for android 100.2.1)
    Android Studio 单元测试
    1.泛型(Generic)
    营销推广软件,抢沙发功能,滑动解锁,自动提交文章评论,使用Puppeteer(一)
    C# 使用Tesseract-OCR-v5.0,实现验证码,中文,身份证识别
    Tesseract-OCR-v5.0中文识别,训练自定义字库,提高图片的识别效果
    C# 实现验证码识别,使用AspriseOCR.dll
    C# 自动批量搜索指定关键字,没有注册的域名
    C#图片采集软件 自动翻页 自动分类(收集美图必备工具)(一)
  • 原文地址:https://www.cnblogs.com/franknihao/p/9396491.html
Copyright © 2011-2022 走看看