面试知识库

169. 多数元素#

大家好!今天我们要聊一个简单却实用的问题——多数元素(Majority Element)。这个问题不仅在算法竞赛中常见,在实际应用中也有着广泛的用途,比如选举系统、数据挖掘和容错计算等。让我们一起探索这个问题的多种解法!

🌟 多数元素:民主选举中的赢家#

什么是”多数元素”?简单来说,就是在一个数组中出现次数超过半数(n/2)的元素。它像是一场选举中获得多数票的候选人,无论其他候选人如何分割选票,这个赢家总是稳操胜券。

问题描述#

题目目标#

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数大于 ⌊n / 2⌋ 的元素。

示例 1#

输入: nums = [2,2,1,1,1,2,2] 输出: 2 说明: 把输入和输出放在一起看,会更容易直接抓住题目要求的变化。

🎯 问题描述:寻找数组中的主导者#

给定一个大小为n的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于⌊n/2⌋的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

例如:

输入: [3,2,3]
输出: 3

输入: [2,2,1,1,1,2,2]
输出: 2
plaintext

🚶‍♀️ 解法一:计数法(直观但不是最优)#

最简单的方法就是用一个哈希表记录每个元素出现的次数,然后找出出现次数最多的元素:

时间复杂度:O(n),需要遍历数组一次
空间复杂度:O(n),哈希表最多存储n个键值对

🏇 解法二:排序后取中间值(优雅但非线性时间)#

一个有趣的洞察:如果将数组排序,那么多数元素一定会出现在数组的中间位置!

class Solution {
    public int majorityElement(int[] nums) {
        // 先对数组升序排序
        Arrays.sort(nums);
        // 多数元素出现次数 > n/2,排序后一定占据中间位置
        return nums[nums.length / 2];
    }
}
java

时间复杂度:O(n log n),排序的时间复杂度
空间复杂度:O(1) 或 O(n),取决于排序算法的实现

这个解法虽然简洁优雅,但由于排序的时间复杂度是O(n log n),不是最优的。

🏆 解法三:摩尔投票法(最优解)#

摩尔投票法是解决这个问题的最佳方法,它利用的是多数元素的特性:出现次数超过一半。

基本思路:将第一个数视为候选多数元素,初始计数为1。遍历数组,如果遇到相同的数,计数加1;如果遇到不同的数,计数减1。当计数变为0时,更换候选多数元素。

时间复杂度:O(n),只需遍历数组一次
空间复杂度:O(1),只使用了常数额外空间

🎭 摩尔投票法的直观理解:士兵对决#

想象一下,数组中的每个元素都是一名士兵,不同的元素代表不同的队伍。摩尔投票法的过程就像是不同队伍的士兵两两对决,每次对决后双方都阵亡一名。

由于多数元素的士兵数量超过总人数的一半,所以无论如何安排对决,最后一定会有多数元素的士兵存活下来!

🎬 图解摩尔投票法#

以输入数组 [2,2,1,1,1,2,2] 为例:

  1. 候选人 = 2,计数 = 1
  2. 遇到2,计数 = 2
  3. 遇到1,计数 = 1
  4. 遇到1,计数 = 0,需要重新选举
  5. 遇到1,候选人 = 1,计数 = 1
  6. 遇到2,计数 = 0,需要重新选举
  7. 遇到2,候选人 = 2,计数 = 1

最终候选人是2,恰好是多数元素。

🔍 为什么摩尔投票法有效?#

摩尔投票法的核心思想是”消除”。每当我们遇到一对不同的元素,我们就将它们”消除”。由于多数元素的数量超过n/2,所以:

  • 如果我们消除了一对不同的元素(一个多数,一个非多数),数组中剩余的多数元素仍然是多数。
  • 即使最坏情况下,所有的非多数元素都与多数元素配对消除,最后剩下的仍然是多数元素。

这就保证了算法的正确性。

🌱 扩展思考:如果不保证存在多数元素?#

如果题目不保证存在多数元素,我们需要在找到候选人后再验证一次:

🌐 实际应用:从投票系统到故障检测#

多数元素的概念在现实中有广泛应用:

  • 分布式系统:使用多数投票确保系统一致性
  • 容错计算:利用冗余和多数表决提高系统可靠性
  • 图像处理:噪声消除中的多数滤波器
  • 数据挖掘:识别数据集中的主要趋势

💯 解题心得:从复杂到简单的思维转变#

解决多数元素问题的过程展示了算法设计中的一个重要思路:从问题的特性出发,寻找最简洁的解法。

  • 哈希表解法是最通用的,但需要额外空间
  • 排序解法洞察了多数元素的位置特性,但时间复杂度较高
  • 摩尔投票法则充分利用了多数元素的数量特性,达到了时间和空间的双重最优

这种从复杂到简单的思维转变是算法设计和优化的精髓所在。

🎓 面试小贴士#

面试中,如果遇到多数元素问题,建议按照以下步骤回答:

  1. 先提出哈希表计数的方法,这是最直观的
  2. 然后提出排序后取中间值的方法,展示你能从不同角度思考问题
  3. 最后介绍摩尔投票法,说明你了解针对特定问题的最优算法
  4. 别忘了讨论如果不保证存在多数元素的情况,这展示了你的全面思考

🤔 思考题#

如果要求找出数组中所有出现次数超过⌊n/3⌋的元素(最多有2个这样的元素),如何修改摩尔投票法来解决这个问题?


多数元素问题是一个看似简单却蕴含丰富思想的问题。它从简单的计数到巧妙的投票算法,展示了算法设计的不同层次和思维方式。希望通过这个问题,你不仅学会了具体的解法,更领悟到了算法设计的美妙之处!

💪 练习建议#

想要真正掌握这个问题,不妨试试这些练习:

  1. 尝试手动模拟摩尔投票法的过程,加深理解
  2. 实现查找数组中出现次数超过n/3的元素
  3. 思考如何处理数据流中的多数元素问题(即元素是一个一个到达的)

记住,算法学习不是记忆解法,而是理解思路和方法。当你能够自然地推导出摩尔投票法,你就真正掌握了这个问题的精髓!