题目:
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:nums = [3,2,3]
输出:3
示例 2:
输入:nums = [2,2,1,1,1,2,2]
输出:2
提示:
-
n == nums.length
-
1 <= n <= 5 * 104
-
-109 <= nums[i] <= 109
思路如下:
-
哈希表统计法: 遍历数组 nums ,用 HashMap 统计各数字的数量,即可找出 众数 。此方法时间和空间复杂度均为 O(N) 。
-
数组排序法: 将数组 nums 排序,数组中点的元素 一定为众数。
-
摩尔投票法: 核心理念为 票数正负抵消 。此方法时间和空间复杂度分别为 O(N) 和 O(1) ,为本题的最佳解法。
题解如下:
#1
class Solution:
def majorityElement(self, nums):
"""
:type: nums: List[int]
:rtype: int
"""
count = {}
m = len(nums) // 2
for i in range(len(nums)):
if nums[i] not in count:
count[nums[i]] = 1
else:
count[nums[i]] += 1
for key in count:
if count[key] > m:
return key
#2
class Solution:
def majorityElement(self, nums):
"""
:type: nums: List[int]
:rtype: int
"""
nums.sort() # 时间复杂度 O(n log n)
return nums[len(nums) // 2]
#3
class Solution:
def majorityElement(self, nums):
"""
:type: nums: List[int]
:rtype: int
"""
votes = 0
for num in nums:
if votes == 0: x = num
votes += 1 if num == x else -1
return x
"""
考虑数组不存在众数的情况,需要加入一个 “验证环节” ,遍历数组 nums 统计 x 的数量。
"""
# 验证 x 是否为众数
for num in nums:
if num == x: count += 1
return x if count > len(nums) // 2 else 0 # 当无众数时返回 0
摩尔投票:
设输入数组 nums 的众数为 x ,数组长度为 n 。
推论一: 若记 众数 的票数为 +1 ,非众数 的票数为 −1 ,则一定有所有数字的 票数和 >0 。
推论二: 若数组的前 a 个数字的 票数和 =0 ,则 数组剩余 (n−a) 个数字的 票数和一定仍 >0 ,即后 (n−a) 个数字的 众数仍为 x 。
根据以上推论,记数组首个元素为 n1,众数为 x ,遍历并统计票数。当发生 票数和 =0 时,剩余数组的众数一定不变 ,这是由于:
-
当 n1 = x : 抵消的所有数字中,有一半是众数 x 。
-
当 n1 != x : 抵消的所有数字中,众数 x 的数量最少为 0 个,最多为一半。
利用此特性,每轮假设发生 票数和 =0 都可以 缩小剩余数组区间 。当遍历完成时,最后一轮假设的数字即为众数。
算法流程:
1.初始化: 票数统计 votes = 0 , 众数 x。
2.循环: 遍历数组 nums 中的每个数字 num 。
-
当 票数 votes 等于 0 ,则假设当前数字 num 是众数。
-
当 num = x 时,票数 votes 自增 1 ;当 num != x 时,票数 votes 自减 1 。
3.返回值: 返回 x 即可。