找出整型数组中占比超过一半的数
问题描述
小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
解题思路
这个问题可以通过 Boyer-Moore 投票算法(Boyer-Moore Voting Algorithm),即摩尔算法来解决。题目给定了一个整数数组,并保证有一个数的出现次数超过数组长度的一半。因为这个数的出现次数超过一半,所以它必然是数组中的众数,即出现次数最多的数。可以利用这个特性来找到它。
Boyer-Moore 投票算法的思路是通过“投票”来找出数组中的众数:
-
初始化一个候选数
candidate和一个计数器count。 -
遍历数组中的每个数:
- 如果
count为 0,意味着之前的候选数被“投票”抵消完了,那么我们将当前数设为新的候选数,并将count设为 1。 - 如果当前数等于候选数,则增加
count。 - 如果当前数不等于候选数,则减少
count。
- 如果
-
由于众数的出现次数超过一半,最后剩下的
candidate必然是众数。
Python代码
def solution(array):
# Edit your code here
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
if __name__ == "__main__":
# Add your test cases here
print(solution([1, 3, 8, 2, 3, 1, 3, 3, 3]) == 3)
关键代码解释
-
candidate = None和count = 0: 初始化候选数和计数器。在遍历数组之前,候选数为空且计数为 0。 -
if count == 0: 当计数器为 0 时,表示前面的候选数和其他数相互抵消。此时,将当前元素num设为新的候选数,并将count重置为 1。 -
elif num == candidate: 如果当前数num等于当前的候选数,则增加count。因为该数支持候选数,所以增加计数。 -
else: count -= 1: 如果当前数num不等于候选数,则减少count。这相当于“投反对票”。
时间和空间复杂度
- 时间复杂度:O(n),其中
n是数组的长度。遍历数组一次即可找出众数。 - 空间复杂度:O(1),只需要常数级的额外空间来存储
candidate和count。