题目解析: 这是一道寻找数组中出现次数超过一半的元素(众数)的问题。关键特点是:
- 保证存在一个数字出现次数超过总数的一半
- 需要找到这个数字(而不是统计次数)
- 要求尽可能高效的解法
关键特征分析:
- 出现次数超过n/2的数字最多只能有一个
- 这个数字一定存在(题目保证)
- 不需要考虑特殊情况(如空数组)
- 不要求保持原数组顺序
解题思路分析:
- 基本解法思路(多种方案):
方案1:哈希表统计法
python
CopyInsert
def find_majority(array):
count_dict = {}
n = len(array)
for num in array:
count_dict[num] = count_dict.get(num, 0) + 1
if count_dict[num] > n // 2:
return num
return array[0] # 因为题目保证存在众数,所以一定会在循环中返回
方案2:排序法
python
CopyInsert
def find_majority(array):
array.sort()
return array[len(array) // 2]
方案3:摩尔投票法(最优解)
python
CopyInsert
def find_majority(array):
candidate = array[0]
count = 1
# 找到候选众数
for num in array[1:]:
if count == 0:
candidate = num
count = 1
elif num == candidate:
count += 1
else:
count -= 1
return candidate
- 各方案分析:
a) 哈希表统计法:
-
优点:
- 直观易理解
- 实现简单
- 只需要遍历一次数组
-
缺点:
- 需要额外空间存储计数
- 不是最优的空间复杂度
b) 排序法:
-
优点:
- 实现最简单
- 不需要额外的数据结构
-
缺点:
- 时间复杂度较高 O(nlogn)
- 改变了原数组顺序
c) 摩尔投票法:
-
优点:
- 时间复杂度最优 O(n)
- 空间复杂度最优 O(1)
- 不改变原数组
-
缺点:
- 理解起来较难
- 不直观
- 摩尔投票法详细解释:
原理:
-
如果一个数出现次数超过n/2,那么它出现的次数减去其他所有数出现的次数仍然大于0
-
可以把这个过程想象成一场选举:
- 候选人获得一票就+1
- 反对票就-1
- 当计数为0时换新候选人
- 最后留下的候选人一定是众数
算法步骤:
-
初始化第一个数为候选人,票数为1
-
遍历数组:
- 如果当前票数为0,更换候选人
- 如果当前数字等于候选人,票数+1
- 如果当前数字不等于候选人,票数-1
-
最后剩下的候选人就是众数
算法复杂度分析:
-
摩尔投票法(最优解):
- 时间复杂度:O(n)
- 空间复杂度:O(1)
-
哈希表方法:
- 时间复杂度:O(n)
- 空间复杂度:O(n)
-
排序方法:
- 时间复杂度:O(nlogn)
- 空间复杂度:O(1)或O(n)(取决于排序算法)
需要注意的边界情况:
- 数组长度为1
- 所有元素相同
- 众数刚好占一半以上
- 数组中有负数
代码优化建议:
-
输入验证:
- 检查数组是否为空
- 检查数组长度是否合法
-
性能优化:
- 使用摩尔投票法
- 避免不必要的内存分配
-
代码可读性:
- 添加适当的注释
- 使用有意义的变量名
- 模块化函数设计
实际应用场景:
- 投票系统
- 数据统计
- 模式识别
- 信号处理
测试用例设计:
-
基本测试:
- 正常的数组输入
- 不同大小的数组
- 不同的众数值
-
边界测试:
- 最小数组(一个元素)
- 所有元素相同
- 众数刚好超过一半
-
特殊测试:
- 负数测试
- 零值测试
- 大数测试
总结: 这道题目的关键点在于:
- 理解问题特性(必定存在众数)
- 选择合适的算法(摩尔投票法最优)
- 正确处理边界情况
- 注意代码的可维护性
学习要点:
- 算法效率的权衡
- 空间复杂度的优化
- 代码实现的技巧
- 实际应用的考虑
这是一道很好的算法题,既可以训练基本编程能力,也能学习到优秀的算法思想。摩尔投票法的思想在其他类似问题中也有应用,值得深入理解。