问题描述
小R从班级中抽取了一些同学,每位同学都会给出一个数字。已知在这些数字中,某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。
测试样例
样例1:
输入:
array = [1, 3, 8, 2, 3, 1, 3, 3, 3]
输出:3
样例2:
输入:
array = [5, 5, 5, 1, 2, 5, 5]
输出:5
样例3:
输入:
array = [9, 9, 9, 9, 8, 9, 8, 8]输出:9
背景介绍
在计算机科学中,寻找数组中出现频率最高的元素是一个经典的问题。 此类问题通常被称为“众数”(Majority Element)问题,特别是当给定条件要求某个元素出现次数超过数组总数的一半时,这种类型的题目在算法和数据结构的学习中具有重要意义。 在实际应用中,这类问题经常出现在统计分析、数据挖掘和推荐系统中。 例如,在某些市场调查中,如果有一个商品的购买次数远超其他商品,就可以认为该商品是市场的主流商品。 在社交媒体中,某个话题或标签的讨论量超过一半,也能代表它是当前的热点话题。 因此,能够高效地找到某个元素是否超过了数组中的一半频率,具有广泛的实际应用场景。
解题思路
这个问题的核心在于,我们需要从一个给定的数字数组中找到一个出现次数超过总数一半的数字。 根据题目条件,可以明确知道,数组中必定有一个数字满足这个条件,因此我们的任务是找出这个数字并返回。
1. 直观的解法——哈希表
最直观的解法是使用一个哈希表来记录每个数字出现的频率。 遍历数组,每遇到一个数字,就在哈希表中更新它的频次。 当某个数字的频次超过数组长度的一半时,我们就可以直接返回该数字 步骤 :
- 遍历数组并维护一个哈希表,其中键是数字,值是该数字出现的次数。
- 在遍历过程中,每次更新哈希表,检查某个数字的出现次数是否超过了数组长度的一半。
- 如果找到了满足条件的数字,就返回该数字。 时间复杂度 :O(n),其中 n 是数组的长度。 我们需要一次遍历数组,并在哈希表中进行操作(平均时间复杂度是O(1))。 空间复杂度:O(n),因为哈希表最多存储 n 个不同的数字。
2. 优化的解法——摩尔投票算法
哈希表的解法虽然直观,但由于需要额外的空间来存储频次数据,空间复杂度是 O(n)。 如果希望优化空间使用,可以使用一种更高效的算法——摩尔投票算法(Boyer-Moore Voting Algorithm)。 摩尔投票算法的核心思想是:在一个数组中,若某个数字出现次数超过一半,那么通过不断“相互抵消”的方法,最终剩下的数字就是我们要找的数字。 算法步骤 :
- 使用两个变量:
candidate(候选数字)和count(候选数字的计数)。 - 遍历数组:
- 如果
count为 0,则将当前数字作为候选数字,并将count置为 1。 - 如果当前数字等于
candidate,则将count增加 1。 - 如果当前数字不等于
candidate,则将count减少 1。
- 如果
- 最终,
candidate就是出现次数超过一半的数字(由于题目保证有解)。 时间复杂度 :O(n),遍历一次数组。 空间复杂度 :O(1),只需要常数空间存储候选数字和计数器。
代码实现
哈希表方法
def majority_element(nums):
# 使用字典来统计数字出现的次数
count = {}
for num in nums:
if num in count:
count[num] += 1
else:
count[num] = 1
# 检查是否超过了一半
if count[num] > len(nums) // 2:
return num
摩尔投票算法方法
def majority_element(nums):
candidate = None
count = 0
for num in nums:
if count == 0:
candidate = num
count += (1 if num == candidate else -1)
# 题目保证有解,不需要额外验证
return candidate