14. 多数元素
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例:
输入:nums = [3,2,3] 输出:3
常用的算法分别是:函数法 Counter、简单数学思维法、投票法、字典法 和 排序法。
函数法 Counter:
使用 Counter 函数计算多数元素的代码思路是:
- 使用 Counter 统计数组 nums 中每个元素出现的次数
- 将 nums 转换成集合 set,如果 set 的长度不超过 nums 长度的一半,则说明存在多数元素
- 通过 max() 和 key 参数,找到出现次数最多的元素,即为多数元素
# 函数法 Counter 时间复杂度:O(n) 空间复杂度:O(n)
def majority_element1(nums):
dict = Counter(nums)
# 返回出现次数最多的那个元素
return max(dict.keys(), key = dict.get)
时间复杂度: O(n),遍历数组统计元素次数为 O(n),,set 操作为 O(n),找到出现最多的元素为 O(n),总体为线性复杂度。
空间复杂度: O(n),使用字典统计数值次数需要线性大小的额外空间。
简单数学思维法:
使用简单数学思维来判断多数元素的代码思路是:
- 计算数组长度 n
- 遍历数组中的每个元素 i
- 使用生成器表达式统计 i 在数组中出现的次数 count
- 如果 count 大于或等于 n的一半,则 i 是多数元素
# 简单数学思维法 时间复杂度:O(n**2) 空间复杂度:O(1)
def majority_element2(nums):
n = len(nums)
for i in nums:
# 当element等于i,返回1,将返回的1累加统计num的出现次数
count = sum(1 for element in nums if element == i)
if count >= math.ceil(n/2):
return i
时间复杂度:O(n^2) ,两层遍历,外层遍历数组元素,内层遍历进行统计计数,时间复杂度是平方级的。
空间复杂度:O(1) ,只需要常数级别的额外空间。
投票法:
使用投票算法求多数元素的代码思路是:
- 先判断数组是否存在多数元素
- 设置一个major变量记录当前可能的多数元素,count变量记录major出现的次数
- 遍历数组,如果遇到与major相同的元素,count++,否则count--
- 如果count变为0,则major更新为当前元素,count重置为1
- 遍历结束后,major就是多数元素
# 投票法 时间复杂度:O(n) 空间复杂度:O(1)
def majority_elements3(nums):
major = count = 0
for n in nums:
if count == 0:
major = n
if n == major:
count += 1
else:
count -= 1
return major
时间复杂度:O(n) ,只需要遍历一次数组即可得到结果,时间复杂度为线性阶。
空间复杂度:O(1) ,只需要两个额外变量major和count,空间复杂度为常数级别。
字典法:
使用字典统计计数的方法的算法思路是:
- 用一个字典dict来统计每个元素出现的次数
- 遍历数组nums,将每个元素num作为dict的键
- 如果num已经在dict中了,则对应的值+1,表示该元素出现次数加1
- 如果num不在dict中,则添加入dict,并将出现次数初始化为1
- 遍历dict中的键值对,如果某个元素的出现次数count大于数组长度的一半,则它就是多数元素
- 返回该元素
# 字典法 时间复杂度:O(n) 空间复杂度:O(n)
def majority_element4(nums):
dict = {}
for num in nums:
if num in dict:
dict[num] += 1
else:
dict[num] = 1
# 遍历字典dict的所有键值对
for num, count in dict.items():
if count > len(nums) // 2:
return num
时间复杂度: O(N),需要遍历一遍数组统计元素频率,然后遍历一遍字典找到多数元素,总体上是线性时间复杂度。
空间复杂度: O(N),需要一个大小为 N 的字典来存储元素频率,因此需要线性的额外空间。
排序法:
使用排序的方法的算法思路是:
- 首先对数组nums进行排序
- 由于多数元素出现的次数大于数组长度的一半
- 排序后,数组中间位置的元素出现次数一定会超过数组长度的一半
- 直接返回排序后数组中mid索引位置的元素,即为多数元素。
# 排序法 时间复杂度:O(nlogn) 空间复杂度:O(1)
def majority_element5(nums):
nums.sort()
return nums[len(nums) // 2]
时间复杂度: O(NlogN),主要消耗在排序算法上的时间。
空间复杂度: O(1),直接在原数组上进行排序,没有占用额外空间。