news 2026/2/28 14:52:14

力扣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/2/28 4:16:43

YOLO与Flagger渐进式交付集成:自动化金丝雀发布

YOLO与Flagger渐进式交付集成&#xff1a;自动化金丝雀发布 在智能制造车间的视觉质检线上&#xff0c;一台边缘设备突然开始频繁漏检微小缺陷——原因竟是刚上线的新版目标检测模型对特定光照条件敏感。这种场景在AI工业化落地过程中屡见不鲜&#xff1a;模型在离线测试中表现…

作者头像 李华
网站建设 2026/2/21 11:19:33

基于FPGA的交通信号灯控制系统设计十字路口交通灯红绿灯控制

详见主页个人简介获取配套设计报告程序源文件截图1引言 1.1 设计目的 1.2 设计任务 1.模拟十字路口交通信号灯的工作过程&#xff0c;利用交通信号灯上的两组红&#xff0c;黄&#xff0c;绿LED发光二极管作为交通信号灯&#xff0c;设计一个交通信号灯控制器。 2.模拟两条公…

作者头像 李华
网站建设 2026/2/26 20:31:15

YOLO模型灰度版本灰度结束后的效果复盘

YOLO模型灰度版本灰度结束后的效果复盘 在智能制造工厂的SMT产线车间里&#xff0c;一块块PCB板正以每分钟200块的速度通过检测工位。过去&#xff0c;这个环节依赖四名质检员轮班盯屏&#xff0c;不仅人力成本高&#xff0c;还常因疲劳导致漏检。而现在&#xff0c;一台搭载Je…

作者头像 李华
网站建设 2026/2/28 9:26:56

Springboot校园交友网站k73q9(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表项目功能&#xff1a;用户,线下活动,交友信息,活动报名开题报告内容基于SpringBoot的校园交友网站开题报告一、研究背景与意义1.1 研究背景随着互联网技术的快速发展&#xff0c;社交方式正经历深刻变革。传统线下交友受限于时间、空间和兴趣匹配度&#xff0c…

作者头像 李华
网站建设 2026/2/26 22:44:44

InfiniBand 网络管理探秘:子网管理器如何发现硬件并分配网络地址

在现代高性能计算和数据中心中,InfiniBand 网络凭借其超低延迟和高吞吐量成为关键基础设施。然而,一个高效网络的运行离不开精密的"交通管理系统"——子网管理器(Subnet Manager,SM)。今天,我们将深入探索 SM 如何从零开始,发现网络中的所有硬件设备,并为它们…

作者头像 李华
网站建设 2026/2/27 11:41:25

年终复盘2.0:NLP自动萃取经验教训,构建可执行策略库

引言&#xff1a;当“复盘”沦为填表运动&#xff0c;组织正在失去什么&#xff1f;每年12月&#xff0c;科技公司纷纷启动年终复盘。然而&#xff0c;IDC《2024企业知识管理报告》揭示了一个残酷现实&#xff1a;87%的复盘最终止步于PPT归档。管理者面对成百上千条员工反馈&am…

作者头像 李华