给定一个大小为n的数组,找到出现次数大于⌊n/2⌋的元素,称之为“多数元素”。假设数组是非空的,且多数元素存在。
方法一:遍历寻找
简单粗暴。去重,遍历每个元素,统计其出现的次数,如果大于⌊n/2⌋,将其返回。
# 方法一:遍历
def maj1(ls):
for i in set(ls):
if ls.count(i) > len(ls)/2:
return i
方法二:统计频数
出现次数大于⌊n/2⌋次的多数元素,一定是数组中出现次数最多的元素,且一定唯一。
所以,可以统计每个元素的频数,找出其中频数最高的。比较专业地说,这就叫构建一个哈希表。
Counter是一个继承了字典的类,至于它是如何显示结果的,我们一看便知:
Counter('abcdeabcdabcaba')
得到一个包含频数统计结果的字典,键是元素,值是元素频数:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})
Counter('abcdeabcdabcaba').most_common(2)
返回一个列表,里面依序包含频数排名前若干位的键值对元组:[('a', 5), ('b', 4)]
# 方法二:统计频数
from collections import Counter
def maj2(ls):
return Counter(ls).most_common(1)[0][0]
方法三:排序
如果将数组按增序排序,那么下标为⌊n/2⌋的元素(下标从0开始)一定是多数元素。
证明:
# 方法三:排序
def maj3(ls):
ls.sort()
return ls[len(ls)//2]
方法四:分治
如果a是多数元素,将数组分成两部分,那么a必定是其中至少一个部分的多数元素。
证明:
所以,可以使用分治法解决这个问题:将数组分成左右两部分,分别求出左半部分的多数元素a1和右半部分的多数元素a2,然后在a1和a2中选出真正的多数元素。
# 方法四:分治
def maj4(nums):
if len(nums) == 1:
return nums[0]
mid_idx = len(nums)//2
left = maj(nums[:mid_idx])
right = maj(nums[mid_idx:])
if left == right:
return left
return left if nums.count(left) >= nums.count(right) else right
最后,给大家出一道思考题。
判断命题是否正确:如果a是众数,将数组分成两部分,那么a必定是其中至少一个部分的众数。
https://leetcode-cn.com/problems/majority-element/solution/duo-shu-yuan-su-by-leetcode-solution/