算法:众数寻找

众数寻找

一、统计法——哈希计数

统计每个元素出现次数,生成“键-值:元素-次数”的哈希表,根据值排序,最大值对应的键即为众数

点击查看代码
def modeSearch(arr):
    c=collections.Counter(arr)
    lis=sorted(c.items(),key=lambda x:x[1])
    return lis[-1][0]

arr=[1,1,3,2,2,1]
print("mode:%d"%modeSearch(arr))

#结果
mode:1

二、特殊众数寻找

1.存在多个众数,且返回较小的众数和出现次数

算法:在统计法的基础上,对哈希表进行排序时先按次数排序(正序),再按元素值排序(倒序)

点击查看代码
def modeSearch(arr):
    c=collections.Counter(arr)
    #先按次数从小到大排序,再按元素值从大到小排序。最终排序后结果:[(3, 1), (2, 3), (1, 3)]
    lis=sorted(c.items(),key=lambda x:(x[1],-x[0]))
    return lis[-1][0]

arr=[1,1,3,2,2,1,2]
print("mode:%d"%modeSearch(arr))

#结果
mode:1
 

2.众数出现次数为序列长度的一半

题目链接:在长度 2N 的数组中找出重复 N 次的元素
数据特征:序列中只有一个元素重复n次,序列长度为2*n,序列中包含n+1个不同元素(即众数个数>1,其余=1)

方法一:哈希

点击查看代码
c=collections.Counter(nums)
#直接使用求最大值对应键的方法
return max(c,key=c.get)
 

方法二:遍历

点击查看代码
#本质仍为哈希,但边遍历边判断
st=[0]*10000
for num in nums:
    st[num]+=1
    if st[num]>1:
        return num
return
 

方法三:随机选取
算法:每次随机选择两个不同的下标,判断它们对应的元素是否相等。如果相等,那么返回任意一个作为答案。
其中使用的Python3中的随机函数详见:https://www.cnblogs.com/ZghzzZyu/p/16139855.html

点击查看代码
n=len(nums)
while True:
    i,j=random.randrange(n),random.randrange(n)
    if i!=j and nums[i]==nums[j]:
        return nums[i]
 

3.众数出现次数超过序列长度的一半

题目链接:多数元素
数据特征:序列中某个元素出现次数大于⌊ n/2 ⌋(长度的一半),其余元素也可出现多次但晓宇长度的一半

方法一:哈希
与之前完全相同(最大值的键)

方法二:排序
算法:排序后序列的中心位置一定为该众数

点击查看代码
n=len(nums)
nums.sort()
return nums[n//2]
 

方法三:摩尔投票法
摩尔投票中重要推论
设数组的长度为n,众数为x
推论1.若众数的投票记为+1,非众数的投票记为-1,则所有数的投票和>0
推论2.若n个数中前m项的投票和为0,则剩余的(n-m)个数的投票和依然>0,后面n-m个数的众数仍为x

推论2中,假设数组的首元素为n1,众数为x,当前n-m项的投票和为0时,后n-m个数的众数不变,因为:
① 若n1=x,即n1就是众数,则在前m个数中,就会有一半(m/2)的数为众数,而因为众数大于n/2,
因此在后n-m个数中,x的个数大于(n-m)/2,因此众数x不变

② 若n1!=x,即n1不是众数,则在前m个数中,众数x的个数最少为0个,最多为m/2个,则由上可得,
剩余的n-m个数中x的个数仍大于(n-m)/2,因此众数x不变

通过此特性,可以不断缩小寻找众数的范围,投票和为0的前m项不用看即可

算法:先令首元素为候选众数,投票数为1。从下一个元素开始,若与候选众数相同投票数加1,不同则减1。当投票数为0时,选择当前数为候选众数,重新开始。

点击查看代码
vote,x=1,nums[0]
for num in nums[1:]:
    if vote == 0:
        vote,x=1,num
        continue
    vote+=1 if num==x else -1
return x
posted @ 2022-05-24 17:02  ZghzzZyu  阅读(240)  评论(0编辑  收藏  举报