【码道初阶】一道经典简单题:多数元素(LeetCode 169)|Boyer-Moore 投票算法详解

多数元素问题是算法面试中最经典的题之一:

给定数组 nums,其中一个元素的出现次数 超过 n/2 ,找出它。

要求:

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

示例:

复制代码
输入: [2,2,1,1,1,2,2]
输出: 2

题目保证多数元素一定存在。


一、核心思想:成对抵消

把数组看成选票,每个数字代表一个候选人。当两个不同的元素相遇时,可以视为一张支持票和一张反对票抵消了。

这就是把直接找最多的元素这个问题,转化成了数组间元素互相竞争计票的问题,思想上能转过这个弯来想到这个点,这便是一道Easy题。

由于多数元素(majority element)的票数大于其它所有元素票数的总和,它无法被完全抵消,因此最终剩下的候选人一定是多数元素。

这个思想催生了著名的 ------ Boyer--Moore Majority Vote Algorithm


二、实现步骤

首先我们要创建两个变量:

  • candidate:当前候选人
  • count:候选人当前的"净票数"

遍历数组的每个元素 num

  1. 如果 count == 0

    说明之前的票已经两两抵消完,可以重选候选人:

    复制代码
    candidate = num
    count = 1
  2. 如果 num == candidate

    复制代码
    count++
  3. 否则:

    复制代码
    count--

最终的 candidate 就是多数元素。


三、正确 Java 实现(O(n) 时间 + O(1) 空间)

java 复制代码
class Solution {
    public int majorityElement(int[] nums) {
        int candidate = 0;
        int count = 0;

        for (int num : nums) {
            if (count == 0) {
                candidate = num;
                count = 1;
            } else if (num == candidate) {
                count++;
            } else {
                count--;
            }
        }

        return candidate;
    }
}

这段代码能通过所有测试用例,是多数投票算法的标准写法。


四、特别提醒(⚠ 初学者最常犯的致命错误)

在实现多数投票算法时,许多同学会错误地写出下面这种版本:

java 复制代码
if (count == 0) {
    candidate = num;
    count = 0;      // ❌ 致命错误!
}

这段代码的问题是:

当 count == 0 且选中新候选人时,却不给它加上当前这一票。

结果是:

  • count 一直保持为 0
  • 根本没有进行投票累积
  • 每次都只是不断更换候选人
  • 于是算法最终返回的是数组的最后一个元素
  • 在测试用例 [3,3,4] 中错误返回 4

正确做法必须是:

java 复制代码
count = 1;   // 当前元素至少贡献一票

这是 Boyer-Moore 算法最关键的地方。

如果这一点写错,整个算法将完全失效。


五、为什么算法可靠?

多数元素出现次数 > n/2,因此:

  • 它的票数比所有其他元素加起来还多
  • 在"抵消"过程中,成对消掉的都是多数元素与非多数元素的票
  • 多数元素永远不可能被完全抵消
  • 并且当 count 归零时,多数元素在数组后面部分必然还会再次出现,重新成为 candidate

因此,算法仅需一次遍历即可确定结果。


六、总结

Boyer-Moore 投票算法是一种极其优雅的线性时间算法,特点:

  • 时间复杂度:O(n)(单次遍历)
  • 空间复杂度:O(1)(仅用两个变量)
  • 适用场景:明确存在多数元素

并且务必牢记:

⚠ 实现时 count = 0 分支必须写成 count = 1,否则算法彻底失效。

掌握了这个技巧,许多相关问题(比如"找出现超过 n/3 的元素"、"找出现 k 次的元素")都能顺藤摸瓜继续拓展。


另一种思路(更简洁):

因为存在一定出现>n/2次的元素,那么对数组进行排序后,在中间的元素就是要找的多数元素。

java 复制代码
import java.util.Arrays;
class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }
}
相关推荐
那个村的李富贵15 小时前
CANN加速下的AIGC“即时翻译”:AI语音克隆与实时变声实战
人工智能·算法·aigc·cann
power 雀儿16 小时前
Scaled Dot-Product Attention 分数计算 C++
算法
琹箐16 小时前
最大堆和最小堆 实现思路
java·开发语言·算法
renhongxia117 小时前
如何基于知识图谱进行故障原因、事故原因推理,需要用到哪些算法
人工智能·深度学习·算法·机器学习·自然语言处理·transformer·知识图谱
坚持就完事了17 小时前
数据结构之树(Java实现)
java·算法
算法备案代理17 小时前
大模型备案与算法备案,企业该如何选择?
人工智能·算法·大模型·算法备案
赛姐在努力.17 小时前
【拓扑排序】-- 算法原理讲解,及实现拓扑排序,附赠热门例题
java·算法·图论
野犬寒鸦18 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
霖霖总总18 小时前
[小技巧66]当自增主键耗尽:MySQL 主键溢出问题深度解析与雪花算法替代方案
mysql·算法
rainbow688918 小时前
深入解析C++STL:map与set底层奥秘
java·数据结构·算法