2026/4/17 23:21:37
网站建设
项目流程
广东企业网站建设多少钱,百度一下你就知道啦,在谷歌上做网站广告要多少钱,哪里学网站开发Java版LeetCode热题100之多数元素#xff1a;从暴力解法到Boyer-Moore投票算法的全面解析 本文约9500字#xff0c;系统性地讲解了LeetCode第169题“多数元素”的多种解法、原理分析、复杂度评估及面试实战技巧。适合准备算法面试或深入理解数据结构与算法的同学阅读。 一、原…Java版LeetCode热题100之多数元素从暴力解法到Boyer-Moore投票算法的全面解析本文约9500字系统性地讲解了LeetCode第169题“多数元素”的多种解法、原理分析、复杂度评估及面试实战技巧。适合准备算法面试或深入理解数据结构与算法的同学阅读。一、原题回顾题目名称多数元素Majority ElementLeetCode编号169难度等级简单但蕴含深刻思想题目描述给定一个大小为n的数组nums返回其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋的元素。你可以假设数组是非空的给定的数组总是存在多数元素。示例示例 1 输入nums [3,2,3] 输出3 示例 2 输入nums [2,2,1,1,1,2,2] 输出2约束条件n nums.length1 n 5 * 10^4-10^9 nums[i] 10^9输入保证数组中一定有一个多数元素。进阶要求尝试设计时间复杂度为O(n)、空间复杂度为O(1)的算法解决此问题。二、原题分析这道题的核心在于如何高效地找出出现次数超过一半的元素关键观察点多数元素唯一存在因为若有两个元素都超过 n/2则总和 n矛盾出现次数 n/2意味着它在数量上绝对占优不需要知道具体出现多少次只需识别出该元素即可。常见的错误思路直接排序后取中间值可行但非最优暴力双重循环统计时间复杂度过高忽略“存在多数元素”这一强前提导致算法冗余。本题的价值在于引导我们从不同角度思考“计数”与“比较”的本质并引出经典的Boyer-Moore 投票算法。三、答案构思五种主流解法概览我们将从暴力 → 哈希 → 排序 → 随机化 → 分治 → 投票算法逐步优化最终达到 O(n) 时间 O(1) 空间的理想解。方法时间复杂度空间复杂度是否满足进阶要求暴力枚举O(n²)O(1)❌哈希表O(n)O(n)❌排序O(n log n)O(log n)❌随机化期望 O(n)O(1)✅概率性分治O(n log n)O(log n)❌Boyer-Moore 投票O(n)O(1)✅✅✅下面逐一详解。四、完整答案与代码实现方法一哈希表HashMap思路用哈希表统计每个元素的出现次数遍历过程中维护最大频次的元素。代码实现importjava.util.*;classSolution{publicintmajorityElement(int[]nums){MapInteger,IntegercountsnewHashMap();intmajorityCountnums.length/2;for(intnum:nums){counts.put(num,counts.getOrDefault(num,0)1);if(counts.get(num)majorityCount){returnnum;// 提前返回优化常数时间}}// 理论上不会执行到这里因题目保证存在多数元素return-1;}}优化点在插入时立即判断是否超过 n/2可提前终止避免二次遍历。代码分析使用getOrDefault简化逻辑利用“多数元素必然存在”的前提可在计数超过阈值时立即返回无需存储所有计数后再遍历。复杂度分析时间复杂度O(n)仅一次遍历空间复杂度O(n)最坏情况下所有元素都不同但题目保证有众数实际空间 n。方法二排序法思路由于多数元素出现 n/2 次无论其值大小排序后必定占据中间位置。例如[2,2,1,1,1,2,2]→ 排序后[1,1,1,2,2,2,2]索引 3即 7/23为 2[3,2,3]→[2,3,3]索引 1 为 3。代码实现importjava.util.Arrays;classSolution{publicintmajorityElement(int[]nums){Arrays.sort(nums);returnnums[nums.length/2];}}代码分析极简代码依赖语言内置排序利用数学性质中位数必为众数。复杂度分析时间复杂度O(n log n)由排序决定空间复杂度O(log n)Java 的Arrays.sort()对基本类型使用双轴快排递归栈深度为 O(log n)。⚠️ 注意若手写堆排序可将空间降至 O(1)但时间仍为 O(n log n)。方法三随机化算法思路由于多数元素占比 50%随机选一个元素它是众数的概率 50%。重复几次几乎必然命中。代码实现importjava.util.Random;classSolution{privateintcountOccurrences(int[]nums,inttarget){intcount0;for(intnum:nums){if(numtarget)count;}returncount;}publicintmajorityElement(int[]nums){RandomrandnewRandom();intnnums.length;intmajorityThresholdn/2;while(true){intcandidatenums[rand.nextInt(n)];if(countOccurrences(nums,candidate)majorityThreshold){returncandidate;}}}}代码分析每次随机选一个下标验证是否为众数虽然理论上可能无限循环但期望尝试次数仅为 2 次几何分布。复杂度分析时间复杂度期望 O(n)最坏 O(∞)实际不可能空间复杂度O(1)。✅ 满足进阶要求概率意义上。方法四分治法Divide and Conquer思路关键性质若 a 是整个数组的众数则 a 至少是左半或右半的众数。证明反证法假设 a 在左半 ≤ l/2 次右半 ≤ r/2 次则总次数 ≤ (l r)/2 n/2与“ n/2”矛盾。因此可递归求解左右子数组的众数再合并比较。代码实现classSolution{// 统计 [lo, hi] 区间内 num 的出现次数privateintcountInRange(int[]nums,intnum,intlo,inthi){intcount0;for(intilo;ihi;i){if(nums[i]num)count;}returncount;}privateintmajorityElementRec(int[]nums,intlo,inthi){// 基线条件单个元素if(lohi)returnnums[lo];intmidlo(hi-lo)/2;intleftCandidatemajorityElementRec(nums,lo,mid);intrightCandidatemajorityElementRec(nums,mid1,hi);// 若左右候选相同直接返回if(leftCandidaterightCandidate){returnleftCandidate;}// 否则统计两者在整个区间中的出现次数intleftCountcountInRange(nums,leftCandidate,lo,hi);intrightCountcountInRange(nums,rightCandidate,lo,hi);returnleftCountrightCount?leftCandidate:rightCandidate;}publicintmajorityElement(int[]nums){returnmajorityElementRec(nums,0,nums.length-1);}}代码分析递归分割数组合并时需 O(n) 时间统计两个候选的全局频次利用“众数必在子区间中占优”的性质。复杂度分析时间复杂度T(n) 2T(n/2) O(n) →O(n log n)主定理空间复杂度O(log n)递归栈深度。方法五Boyer-Moore 投票算法最优解思路核心思想多数元素“抵消”其他元素后仍有剩余。维护一个候选candidate和计数器count遍历数组若count 0则更新candidate current若当前元素 candidatecount否则count--最终candidate即为众数。为什么有效因为众数数量 其他所有元素之和所以“一对一抵消”后众数必胜。代码实现简洁版classSolution{publicintmajorityElement(int[]nums){intcount0;Integercandidatenull;for(intnum:nums){if(count0){candidatenum;}count(numcandidate)?1:-1;}returncandidate;// 题目保证存在无需验证}}正确性证明直观理解以[7,7,5,7,5,1,5,7,5,5,7,7,7,7,7,7]为例元素7757515755777777cand7777775555557777cnt1212101012101234每当count0意味着此前的子数组中无绝对优势元素新一轮从当前位置开始“重新计票”由于众数整体占优最后一轮的candidate必为众数。注意若题目不保证存在多数元素需在最后加一步验证遍历统计candidate是否 n/2。复杂度分析时间复杂度O(n)仅一次遍历空间复杂度O(1)仅用两个变量。✅完美满足进阶要求五、时间复杂度与空间复杂度对比总结方法时间复杂度空间复杂度是否稳定是否满足进阶暴力O(n²)O(1)是❌哈希表O(n)O(n)是❌排序O(n log n)O(log n)是❌随机化期望 O(n)O(1)否概率✅弱分治O(n log n)O(log n)是❌Boyer-MooreO(n)O(1)是✅✅✅结论在确定存在多数元素的前提下Boyer-Moore 投票算法是最优解。六、常见问题解答FAQQ1为什么排序后中间元素一定是众数因为众数出现 n/2 次即使全部集中在一端也会“覆盖”中位数位置。例如 n7众数至少出现 4 次无论怎么排第 4 个位置索引 3必为其值。Q2Boyer-Moore 算法能用于“找出现次数最多的元素”吗不能它仅适用于“存在出现次数 n/2 的元素”的场景。若只是找频率最高的如 top-1需用哈希表。Q3如果数组中没有多数元素怎么办Boyer-Moore 仍会返回一个candidate但需二次验证// 验证 candidate 是否真的 n/2intcount0;for(intnum:nums)if(numcandidate)count;returncountnums.length/2?candidate:-1;Q4随机化算法会不会超时几乎不会。期望尝试 2 次每次 O(n)总期望时间 2n。即使尝试 10 次概率也极低 0.1%。七、优化思路与工程实践建议1.优先选择 Boyer-Moore代码简洁、效率高、空间省适用于流式数据无法存储全部元素时。2.哈希表 vs 投票算法若需同时获取所有元素频次用哈希表若仅需众数用投票算法。3.排序法的适用场景当数组已部分有序或后续还需其他顺序操作时代码最短适合快速原型。4.避免暴力解法O(n²) 在 n5e4 时操作次数达 2.5e9必然超时。八、数据结构与算法基础知识点回顾1.哈希表HashMap平均 O(1) 插入/查询底层数组 链表/红黑树Java 8适用于“计数”、“去重”、“映射”场景。2.分治思想将大问题分解为相似子问题典型应用归并排序、快速排序、线段树时间复杂度常用主定理分析。3.随机化算法利用概率降低期望复杂度常见于快速选择、蒙特卡洛方法需注意最坏情况虽概率极低。4.Boyer-Moore 投票算法属于在线算法online algorithm核心利用“多数”与“少数”的数量差可扩展至“找出现 n/k 的元素”需 k-1 个计数器。九、面试官提问环节模拟Q你能解释一下 Boyer-Moore 算法为什么正确吗答因为多数元素出现次数超过一半所以在“一对一抵消”过程中其他所有元素合起来也无法完全抵消它。算法通过维护一个候选和计数器模拟这一抵消过程。当计数器归零时说明此前的子数组中无绝对优势元素于是从当前位置重新开始。由于整体上众数占优最后一轮的候选必为众数。Q如果要找出现次数超过 n/3 的元素可能有0、1或2个怎么做答可扩展 Boyer-Moore 思想维护两个候选和两个计数器。遍历时若当前元素等于任一候选对应计数器1若有计数器为0替换该候选否则两个计数器都-1。最后需验证两个候选是否真的 n/3。这就是LeetCode 229. 求众数 II的解法。Q这个算法能用于数据流streaming data吗答完全可以Boyer-Moore 是典型的单遍扫描、常数空间算法非常适合处理无法全部加载到内存的大数据流。每来一个新元素更新candidate和count即可无需回溯。十、这道算法题在实际开发中的应用1.分布式系统中的共识机制在 Paxos、Raft 等协议中“多数派”决策是核心类似思想只要超过半数节点同意即可达成一致。2.实时数据分析监控系统中识别“高频异常事件”如某 IP 在短时间内发起 50% 的请求可能是 DDoS 攻击。3.投票系统选举中得票过半者胜出算法可快速识别领先者假设数据按时间流式到达。4.缓存淘汰策略LRU 等策略需统计访问频次若某资源访问量突增50%可优先缓存。十一、相关题目推荐题号题目难度关联点229求众数 II中等扩展找 n/3 的元素1207独一无二的出现次数简单哈希表计数387字符串中的第一个唯一字符简单计数 遍历509斐波那契数简单对比非计数类问题217存在重复元素简单哈希表去重重点练习 229 题它是本题的自然延伸。十二、总结与延伸核心收获多数元素问题的本质是“数量优势”而非“值的大小”Boyer-Moore 投票算法是解决此类问题的最优方案体现了“抵消思想”的巧妙算法选择需结合问题约束如“保证存在众数”从暴力到最优体现了算法优化的典型路径空间换时间 → 利用数学性质 → 在线处理。延伸思考能否在 O(1) 空间内找到 top-k 频繁元素→ 一般不能但若 k 固定如 k2可用扩展投票法。如果数组是只读的且不能修改还能用投票算法吗→ 可以投票算法不要求修改原数组。在 GPU 或并行计算中如何加速→ 分治法天然适合并行各子区间独立计算候选最后合并。最后的话LeetCode 169 题看似简单却蕴含了哈希、排序、分治、随机化、在线算法等多种思想。掌握它不仅是为了通过面试更是为了培养从问题本质出发设计算法的能力。记住最优解往往来自于对问题约束的深刻理解而非盲目套用模板。