找出整型数组中占比超过一半的数 | 豆包MarsCode AI刷题

59 阅读3分钟

题目解析

这是一道经典的多数元素问题。题目要求从一个数组中找到出现次数超过总数一半的数字,并确保在输入满足条件的情况下输出正确结果。如果输入的数字中没有满足条件的数字,返回 None。题目中的关键点是:

  1. 找到一个数字,该数字的出现次数严格大于数组长度的一半。

  2. 解决方案需要时间复杂度为 O(n),空间复杂度为 O(1)。

这是一个典型的“摩尔投票算法”(Boyer-Moore Majority Vote Algorithm)问题,该算法通过一次遍历数组,使用一个计数器和候选变量高效地实现了所需功能。

解题思路

摩尔投票算法的核心思想是通过抵消机制找到一个候选元素,并最终验证其是否为多数元素。具体思路如下:

  1. 候选阶段

• 遍历数组并维护一个计数器 count 和候选数字 candidate。

• 初始化时,候选数字为空,计数器为 0。

• 每次遇到一个数字:

• 如果计数器为 0,则将该数字设为候选数字,并将计数器重置为 1。

• 如果数字等于候选数字,则计数器加 1;否则计数器减 1。

• 当遍历完成时,计数器为 0 的数字已经被全部抵消,剩下的候选数字可能是多数元素。

  1. 验证阶段

• 候选阶段只是找到了一个“可能的多数元素”,但为了确保正确性,需再进行一次验证。

• 验证时统计候选数字在数组中的出现次数,若大于数组长度的一半,则返回该数字;否则返回 None。

该方法能够在 O(n) 的时间复杂度内完成,并且只使用常数空间,不依赖额外的数据结构,是一种高效的解决方案。

代码详解

第一部分:候选阶段

• 候选阶段的目的是通过“抵消”找到一个可能的多数元素。抵消的本质是利用数组的性质,剔除掉那些不可能成为多数元素的数字。

• 候选数字 candidate 的变化规则:

• 如果计数器为 0,则当前数字成为新的候选数字。

• 如果当前数字与候选数字相同,则增加计数器;否则,减少计数器。

• 这一过程的时间复杂度为 O(n),因为每个数字只需要一次处理。

第二部分:验证阶段

• 候选阶段并不能保证最终找到的候选数字一定是多数元素,因此需要对候选数字进行验证。

• 验证通过统计候选数字的出现次数实现。如果其出现次数大于数组长度的一半,则返回该数字;否则返回 None。

• 验证过程的时间复杂度为 O(n),因为需要遍历整个数组。

代码优点:

时间复杂度:候选阶段和验证阶段均只需线性时间,因此整体复杂度为 O(n)。

空间复杂度:仅使用常数空间(一个候选变量和一个计数器),即 O(1)。

简单直观:代码逻辑清晰,易于实现和理解。

总结

摩尔投票算法是一种高效解决多数元素问题的经典算法,核心思想是利用计数器和抵消机制找到可能的候选元素,并通过验证确保其正确性。通过一次遍历找到候选元素,再次遍历验证候选元素的出现次数,算法避免了使用额外数据结构存储中间结果,最大限度地优化了空间复杂度。