注: 本系列仅为个人学习笔记,学习内容为《算法小讲堂》(视频传送门),通俗易懂适合编程入门小白,需要具备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