news 2026/4/18 10:29:03

力扣169:多数元素-抵消法和哈希表

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
力扣169:多数元素-抵消法和哈希表

题目描述

给定一个大小为 n 的数组 nums,返回其中的多数元素。多数元素是指在数组中出现次数大于 ⌊n/2⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

方法一:摩尔投票法(最优解)

核心思想

这个算法基于一个关键的抵消思想:由于多数元素的数量超过总数的一半,那么多数元素与其他元素一一抵消后,最后剩下的必然是多数元素。

算法步骤

  1. 初始化候选元素candidate和计数器count为 0

  2. 遍历数组中的每个元素:

    • 如果count为 0,将当前元素设为候选元素

    • 如果当前元素等于候选元素,count加 1

    • 如果当前元素不等于候选元素,count减 1

  3. 遍历结束后,候选元素就是多数元素

代码实现

class Solution { public int majorityElement(int[] nums) { int ans = 0; // 存储当前候选的多数元素 int hp = 0; // 计数器,表示当前候选元素的"生命值" for (int x : nums) { if (hp == 0) { // 生命值为0,需要新的候选 ans = x; // 设置x为新的候选元素 hp = 1; // 初始生命值为1 } else { // 已经有候选元素 if (ans == x) { // 如果当前元素和候选相同 hp += 1; // 生命值+1(支持者增加) } else { // 如果当前元素和候选不同 hp -= 1; // 生命值-1(相互抵消) } } } return ans; // 最终剩下的候选就是多数元素 } }
//简化 class Solution { public int majorityElement(int[] nums) { int ans = 0; int hp = 0; for (int num : nums) { if (hp == 0) { ans = num; } count += (num == ans) ? 1 : -1; } return ans; } }

复杂度分析

  • 时间复杂度:O(n),只需遍历一次数组

  • 空间复杂度:O(1),只使用了常数级别的额外空间

算法优势

这是解决多数元素问题的最优算法,特别适合空间要求严格的场景。它巧妙地将问题转化为"擂台比武",每个元素要么支持当前候选(同门师兄弟),要么反对(敌人),最终多数元素会胜出。

方法二:哈希表法(最直观)

核心思想

使用哈希表记录每个元素出现的次数,然后找到出现次数超过一半的元素。这是最直观的解法,也是面试中最容易想到的方法。

算法步骤

  1. 创建一个哈希表来记录每个数字出现的次数

  2. 遍历数组,更新哈希表中每个数字的计数

  3. 遍历哈希表,找到出现次数超过 n/2 的元素

代码实现

class Solution { public int majorityElement(int[] nums) { // 创建哈希表 Map<Integer, Integer> countMap = new HashMap<>(); // 统计每个数字出现的次数 for (int num : nums) { countMap.put(num, countMap.getOrDefault(num, 0) + 1); // 可以在统计过程中直接判断,提高效率 if (countMap.get(num) > nums.length / 2) { return num; } } // 理论上不会执行到这里 return -1; } }

简化版本

class Solution { public int majorityElement(int[] nums) { Map<Integer, Integer> map = new HashMap<>(); int maxCount = 0; int result = 0; for (int num : nums) { int count = map.getOrDefault(num, 0) + 1; map.put(num, count); // 在遍历过程中更新最大值 if (count > maxCount) { maxCount = count; result = num; } } return result; } }

复杂度分析

  • 时间复杂度:O(n),需要遍历一次数组,哈希表操作平均O(1)

  • 空间复杂度:O(k),其中k是数组中不同元素的数量,最坏情况下为O(n)

方法对比与选择建议

特性Boyer-Moore算法哈希表统计法
时间复杂度O(n)O(n)
空间复杂度O(1)O(n)
实现难度中等(需要理解算法原理)简单(直观易懂)
是否需要验证需要(如果不确定存在多数元素)不需要(遍历时即可判断)
实际性能更快(常数时间小)稍慢(哈希表操作有开销)
适用场景空间限制严格时代码可读性优先时

选择建议

  1. 面试场景:先讲解Boyer-Moore算法,展示算法优化思想

  2. 实际工作:如果对空间要求不高,使用哈希表法更稳妥

  3. 比赛/刷题:追求极致性能用Boyer-Moore,追求快速实现用哈希表

常见变种问题

1. 寻找出现次数超过 n/3 的元素

class Solution { public List<Integer> majorityElement(int[] nums) { // 最多有两个这样的元素 List<Integer> result = new ArrayList<>(); // 使用Boyer-Moore算法的扩展版本 int candidate1 = 0, candidate2 = 0; int count1 = 0, count2 = 0; for (int num : nums) { if (num == candidate1) { count1++; } else if (num == candidate2) { count2++; } else if (count1 == 0) { candidate1 = num; count1 = 1; } else if (count2 == 0) { candidate2 = num; count2 = 1; } else { count1--; count2--; } } // 验证候选元素是否真的超过n/3 count1 = 0; count2 = 0; for (int num : nums) { if (num == candidate1) count1++; else if (num == candidate2) count2++; } if (count1 > nums.length / 3) result.add(candidate1); if (count2 > nums.length / 3) result.add(candidate2); return result; } }

2. 寻找出现次数最多的元素(众数)

class Solution { public int majorityElement(int[] nums) { // 使用哈希表统计频率 Map<Integer, Integer> countMap = new HashMap<>(); int maxCount = 0; int result = nums[0]; for (int num : nums) { int count = countMap.getOrDefault(num, 0) + 1; countMap.put(num, count); if (count > maxCount) { maxCount = count; result = num; } } return result; } }

总结

多数元素问题是一个经典的算法问题,展示了不同解法之间的权衡:

  1. Boyer-Moore投票算法是空间最优解,体现了算法设计的巧妙性

  2. 哈希表统计法是最直观的解,易于理解和实现

  3. 排序法虽然简单,但时间复杂度较高

  4. 分治法展示了递归解决问题的思路

在实际应用中,根据具体需求选择合适的解法。如果空间限制严格,Boyer-Moore算法是最佳选择;如果追求代码可读性和维护性,哈希表法更合适。无论选择哪种方法,理解其背后的原理和适用场景才是最重要的。

刷题建议:掌握Boyer-Moore算法的思想和实现,这在面试中经常被考察。同时也要熟悉哈希表解法,因为它适用于更广泛的统计问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 13:30:26

YOLO与Prometheus Thanos Ruler集成:跨集群告警规则

YOLO与Prometheus Thanos Ruler集成&#xff1a;跨集群告警规则 在智慧园区、智能制造和边缘视觉分析等场景中&#xff0c;一个日益突出的挑战是&#xff1a;如何将AI推理服务的“智能输出”真正纳入企业级监控体系&#xff1f;传统的做法往往是把YOLO这类目标检测模型当作黑盒…

作者头像 李华
网站建设 2026/4/18 7:24:58

STL专项:vector 变长数组

以下内容为学习过程中所记录的笔记 推荐引入万能头文件 #include<bits/stdc.h> //万能头文件 / 预编译头文件&#xff0c;它的本质是包含了 C 标准库中几乎所有常用的头文件&#xff08;比如输入输出、字符串、容器、算法、数学函数等&#xff09; using namespa…

作者头像 李华
网站建设 2026/4/18 11:04:19

YOLO模型训练资源使用趋势预测:基于历史数据分析

YOLO模型训练资源使用趋势预测&#xff1a;基于历史数据分析 在智能制造工厂的质检线上&#xff0c;一台AOI&#xff08;自动光学检测&#xff09;设备每秒拍摄数十张PCB板图像&#xff0c;系统必须在200毫秒内完成缺陷识别并决定是否停机。这样的高实时性要求背后&#xff0c;…

作者头像 李华
网站建设 2026/4/18 7:31:55

采样率、信号频谱/频谱混叠原理与matlab仿真分析

目录 1.采样率(fs​)与采样定理——奈奎斯特采样定理 2.信号的频谱分析 连续信号 离散信号 3.频谱混叠 1.采样率(fs​)与采样定理——奈奎斯特采样定理 采样率是指对连续模拟信号进行离散化时&#xff0c;每秒采集的样本点数&#xff0c;单位为Hz(赫兹&#xff0c;1Hz1个样…

作者头像 李华
网站建设 2026/4/17 22:37:27

《创业之路》-761-《架构思维:从程序员到CTO》第四部 - 架构师的职业规划与能力成长:从执行者到战略引领者的跃迁,技术、业务与软技能的三角支撑。

一、职业规划&#xff1a;从执行者到战略引领者的跃迁阶段划分与目标设定短期&#xff08;1-3年&#xff09;&#xff1a;夯实技术基础&#xff0c;掌握至少一门主流编程语言&#xff08;如Java、Python&#xff09;&#xff0c;熟悉分布式系统、微服务架构等设计理念&#xff…

作者头像 李华