题解:找出整型数组中占比超过一半的数

74 阅读3分钟

问题描述

小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

解题思路

排序做法

思路
如果一个数列存在主元素,那么该主元素在排序后必然出现在索引 n/2 的位置。

sort(a, a + n);
cout << a[n / 2];

时间复杂度: O(nlog⁡n)

桶计数做法

思路
统计每个数字出现的次数,找到出现次数超过 n / 2 的元素。

时间复杂度: O(n),空间复杂度:O(m)。

代码实现

from collections import defaultdict

def find_majority_bucket(nums):
    count = defaultdict(int)
    n = len(nums)
    for num in nums:
        count[num] += 1
        if count[num] > n // 2:
            return num

摩尔投票法

思路
利用一个变量 candidate 保存当前候选主元素,另一个变量 count 记录其“票数”,通过一遍遍历找到可能的候选主元素,然后验证它是否确实是主元素。

算法步骤

  1. 初始化 candidatecount

  2. 遍历数组:

    • 如果 count 为 0,则将当前元素设为 candidate,并将 count 设为 1。
    • 如果当前元素等于 candidate,则 count 加 1。
    • 如果当前元素不等于 candidate,则 count 减 1。
  3. 验证 candidate 是否是主元素。

时间复杂度: O(n),空间复杂度: O(1)。

代码实现


def solution(array):

    # 初始化候选元素和计数器

    candidate = None

    count = 0

    

    # 遍历数组,进行投票

    for num in array:

        if count == 0:

            # 如果计数器为0,更新候选元素

            candidate = num

            count = 1

        elif num == candidate:

            # 如果当前元素与候选元素相同,计数器加1

            count += 1

        else:

            # 如果当前元素与候选元素不同,计数器减1

            count -= 1


    return candidate

if __name__ == "__main__":

    # 测试样例

    print(solution([138231333]) == 3)

    print(solution([5551255]) == 5)

    print(solution([99998988]) == 9)

关键点

  • 摩尔投票算法:通过投票机制,高效地找到数组中出现次数超过一半的元素。
  • 时间复杂度:O(n),遍历数组两次。
  • 空间复杂度:O(1),只使用了常数级别的额外空间。

比较

方法时间复杂度空间复杂度特点
排序做法O(nlog⁡n)O(1)简单直接,但时间复杂度稍高
桶计数做法O(n)O(m)快速,但空间复杂度取决于数值范围
摩尔投票法O(n)O(1)高效,适合数值范围较大的情况,需验证候选元素

总结

通过使用摩尔投票算法,我们可以在 O(n) 的时间复杂度和 O(1) 的空间复杂度内,高效地找到数组中出现次数超过一半的元素。这个算法非常适合解决这类问题,并且在实际应用中也非常实用。