学习笔记:找出整型数组中占比超过一半的数
问题描述
给定一个整型数组,数组中某个数字的出现次数超过了数组长度的一半,要求找出这个数字。
关键点
- 题目本质:寻找数组中占比超过一半的元素,即出现次数大于 ⌊n/2⌋ 次的元素。
- 由于该元素出现次数超过了数组总长度的一半,因此在数组中它的数量一定是最多的。
解法思路
根据这个特点,我们可以使用一种非常高效的算法:摩尔投票法 (Boyer-Moore Voting Algorithm)。
摩尔投票法
摩尔投票法的核心思想是:通过一轮遍历,使用计数器消除不同的元素,最终剩下的那个元素就是占比超过一半的数。
算法步骤:
1. 初始化两个变量:
- candidate:记录当前的候选元素;
- count:记录候选元素的计数。
2. 遍历数组中的每个元素:
- 如果 count 为 0,则将当前元素设置为 candidate,并将 count 设为 1。
- 如果当前元素等于 candidate,则 count 加 1。
- 如果当前元素不等于 candidate,则 count 减 1。
3. 最终 candidate 就是占比超过一半的元素。
算法证明
该算法可以保证在多次不同元素的抵消过程中,超过一半的那个元素不会被完全抵消掉。因此,遍历结束时的 candidate 就是我们要找的占比超过一半的元素。
代码实现
def majority_element(array):
candidate = None
count = 0
# 摩尔投票法第一阶段:找到候选元素
for num in array:
if count == 0:
candidate = num
count = 1
elif num == candidate:
count += 1
else:
count -= 1
# 根据题目假设,数组中一定有一个元素占比超过一半,所以不需要第二轮验证
return candidate
测试样例
# 样例1
array1 = [1, 3, 8, 2, 3, 1, 3, 3, 3]
print(majority_element(array1)) # 输出:3
# 样例2
array2 = [5, 5, 5, 1, 2, 5, 5]
print(majority_element(array2)) # 输出:5
# 样例3
array3 = [9, 9, 9, 9, 8, 9, 8, 8]
print(majority_element(array3)) # 输出:9
心得体会
1. 摩尔投票法的优势:该算法的时间复杂度为 O(n),且只需常数级别的额外空间,即 O(1)。相比于其他方法(如哈希表统计频次),它的空间复杂度更低,非常高效。
2. 问题的特点:由于题目假设存在一个出现次数超过数组长度一半的元素,因此可以省略第二轮验证。在实际应用中,如果没有这个假设,则需要在第一阶段找出候选元素后,再进行一次遍历验证该元素的出现次数是否超过一半。
3. 扩展思考:摩尔投票法不仅可以用于解决该问题,还可以应用于类似的需要找出数组中频率最高元素的问题。