1. 概述

在本文中,我们将讨论如何查找数组中的多数元素(Majority Element)。多数元素指的是在数组中出现次数超过一半的元素。我们首先介绍该问题的定义,然后提供三种不同的解决方案,分析它们的优缺点。

2. 问题定义

多数元素是指在长度为 n 的数组中出现次数至少为 ⌈n/2⌉ 的元素。
例如,如果数组长度是 7,则多数元素至少要出现 4 次(即 ⌈7/2⌉)。

来看一个例子:

1, 2, 1, 1, 2, 3, 4

在这个数组中,出现次数最多的数字是 1,共出现 3 次,未达到 4 次的阈值,因此该数组中不存在多数元素。

如果我们把最后一个元素 4 改为 1:

1, 2, 1, 1, 2, 3, 1

此时数字 1 出现了 4 次,满足多数元素的条件,因此 1 是这个数组的多数元素。

3. 简单方法(暴力统计)

一种直观的解决方案是使用哈希表(如 Java 中的 HashMap)来统计每个元素的出现次数,然后找出出现次数最多的那个元素,判断是否满足多数元素的条件。

示例代码

public static Object findMajority(int[] nums) {
    Map<Integer, Integer> frequencyMap = new HashMap<>();
    int n = nums.length;

    for (int num : nums) {
        frequencyMap.put(num, frequencyMap.getOrDefault(num, 0) + 1);
    }

    for (Map.Entry<Integer, Integer> entry : frequencyMap.entrySet()) {
        if (entry.getValue() > n / 2) {
            return entry.getKey();
        }
    }

    return "No majority element";
}

优缺点分析

优点:实现简单,逻辑清晰
缺点:空间复杂度为 O(n),需要额外存储所有元素的频率

4. 排序法(中位数判断)

对数组进行排序后,中间位置的元素(即中位数)可能是多数元素。因为如果存在多数元素,它必定会出现在中间位置。

示例代码

public static Object findMajority(int[] nums) {
    Arrays.sort(nums);
    int n = nums.length;
    int candidate = nums[(n + 1) / 2];
    int count = 0;

    for (int num : nums) {
        if (num == candidate) {
            count++;
        }
    }

    if (count > n / 2) {
        return candidate;
    } else {
        return "No majority element";
    }
}

优缺点分析

优点:空间复杂度较低(O(1) 如果排序是原地进行)
缺点:时间复杂度为 O(n log n),不适用于大规模数据

5. Boyer-Moore 投票算法(最优解)

这是目前最高效的解决方案:Boyer-Moore 多数投票算法。它可以在 O(n) 时间复杂度和 O(1) 空间复杂度下找出可能的多数元素。

核心思想

使用两个变量:

  • candidate:当前可能的多数元素
  • count:计数器,用于投票机制

遍历数组时:

  • 如果 count == 0,更新 candidate 为当前元素,count = 1
  • 如果当前元素等于 candidatecount++
  • 否则,count--

遍历结束后,再次遍历数组确认 candidate 是否真的为多数元素。

示例代码

public static Object findMajority(int[] nums) {
    if (nums.length == 0) return "No majority element";

    int candidate = nums[0];
    int count = 1;

    for (int i = 1; i < nums.length; i++) {
        if (count == 0) {
            candidate = nums[i];
            count = 1;
        } else if (nums[i] == candidate) {
            count++;
        } else {
            count--;
        }
    }

    // 验证 candidate 是否为多数元素
    int freq = 0;
    for (int num : nums) {
        if (num == candidate) {
            freq++;
        }
    }

    if (freq > nums.length / 2) {
        return candidate;
    } else {
        return "No majority element";
    }
}

示例图解

Boyer-Moore 算法执行流程

上图展示了在数组 [1, 2, 1, 1, 2, 3, 1] 上的执行过程。最终 candidate 是 1,且其频率为 4,满足多数元素条件。

优缺点分析

优点

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

缺点:需要两次遍历(一次找候选,一次验证)

6. 算法对比

算法名称 时间复杂度 空间复杂度
哈希统计法 O(n) O(n)
排序法(中位数) O(n log n) O(log n)
Boyer-Moore 算法 ✅ O(n) ✅ O(1)

结论:Boyer-Moore 是目前最优的解决方案,适用于大规模数据处理。

7. 总结

本文介绍了三种查找数组中多数元素的算法:

  • 哈希统计法:实现简单,但空间复杂度高
  • 排序法:利用中位数性质,但时间复杂度较高
  • Boyer-Moore 投票算法:时间 O(n),空间 O(1),是最优选择

在实际开发中,尤其是在处理大数据量时,建议优先使用 Boyer-Moore 算法。它不仅高效,而且易于实现,是解决多数元素问题的标准方案。


原始标题:Find the Majority Element of an Array

» 下一篇: 缓存内存简介