【趣味学算法】10_摩尔投票法

注: 本系列仅为个人学习笔记,学习内容为《算法小讲堂》(视频传送门),通俗易懂适合编程入门小白,需要具备python语言基础,本人小白,如内容有误感谢您的批评指正

现有列表:[2, 2, 4, 2, 3, 6, 2],其中占比超过一半的元素称之为主要元素,请问如何获取列表中的主要元素呢?

让我们先看看其中一种实现思路,根据主要元素的定义,对列表进行排序操作之后,主要元素必然会出现在列表长度一半之后的一个位置上。我们只需要判断列表中是否有超过一半的元素与中间元素相同即可(如果有,中间元素为主要元素;否则,不存在主要元素)。换言之,就是要要遍历整个列表对中间元素出现的次数进行计数,如果计数大于列表长度的一半即为主要元素。

代码实现

nums = [2, 2, 4, 2, 3, 6, 2]
nums.sort()

count = 0
length = len(nums)
half = nums[length//2]

for each in nums:
    if each == half:
        count += 1

if count > length//2:
    print('主要元素为:{}'.format(half))
else:
    print("不存在主要元素")

输出结果:

主要元素为:2

除了以上思路外还有一个思路,就是著名的摩尔投票法(Boyer–Moore majority vote),也被称为“多数投票法”,该算法解决的问题是如何在任意多的候选人中(选票无序),找到获得票数最多的那个。摩尔投票法分为两个阶段:

  • 对抗阶段:分属两个候选人的票数进行两两对抗抵消
  • 计数阶段:计算对抗结果中最后留下的候选人票数是否有效

举个例子说明,假设有三个国家打仗,A国有6个人,B国有11个人,C国有4个人,且都只能一对一打就抵消人头,那么谁会是最终赢家呢?当然是B国啦,跟A国和C国对抗抵消人头后只有B国剩余一人,B国有11个人超过三个国家总人数21的一半,那么它就是最终赢家。

接下来代码实现对抗和计数,先将主要元素初始化为第一个元素,对抗阶段就遍历获取列表中的数字,与主要元素比较,如果相等那么计数+1,如果不等就抵消掉,计数-1,当计数为0时,将下一个元素设为主要元素继续对抗抵消,遍历完后,判断最终赢家的总数量时候否符合超过半数的要求即可

代码实现:

nums = [2, 2, 4, 2, 3, 6, 2]
major = nums[0]
count = 0

for each in nums:
    if count == 0:
        major = each
    if each == major:
        count += 1
    else:
        count -= 1

if nums.count(major)>len(nums)//2:
    print('主要元素为:{}'.format(major))
else:
    print('不存在主要元素')

输出结果

主要元素为:2

在让我们提升一下难度,假设有列表[1,2,1,1,3,1,2,3,2,2,1]利用“摩尔投票法”来找出占比数量最多的两个元素(注意:这两个元素的数量都需要超过总数的三分之一)

实现思路同样是采用对抗然后判断计数的方式,最开始遍历主要判断第一个主要元素,当它的count为0时说明前一部分都被抵消掉了,那遍历至下一个元素时判断的是第二个主要元素

代码实现:

nums = [1,2,1,1,3,1,2,3,2,2,1]
major1 =  major2 = nums[0]
count2 = count1 = 0

for each in nums:
    if major1 == each:
        count1 += 1
        continue
    
    if major2 == each:
        count1 += 1
        continue
    
    if count1 == 0:
        major1 = each
        count1 = 1
        continue
    
    if count2 == 0:
        major2 = each
        count2 = 1
        continue

        count1 -= 1
        count2 -= 1

if nums.count(major1)>len(nums)//3 and nums.count(major2)>len(nums)//3:
    print('主要元素为:{},{}'.format(major1,major2))
else:
    print('不存在两个主要元素')
主要元素为:1,2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值