多数元素问题要求我们找出在数组中出现次数超过 ⌊n/2⌋ 次的元素。这个看似简单的问题背后蕴含着多种算法思想,从最直观的暴力解法到巧妙的数学技巧,每种方法都值得深入探讨。
最直接的思路是遍历数组中的每个元素,然后嵌套遍历统计该元素出现的次数。当某个元素的计数超过阈值时立即返回。这种方法虽然直观,但时间复杂度达到了O(n²),在LeetCode上提交会导致超时。
python复制def majorityElement(nums):
majority_count = len(nums)//2
for num in nums:
count = 0
for elem in nums:
if elem == num:
count += 1
if count > majority_count:
return num
注意:在实际面试中,即使你能想到更优解法,也应该先提出这种基础解法,然后分析其缺点,再逐步优化。这展示了你的思维过程。
使用哈希表记录每个元素的出现次数,可以将时间复杂度降到O(n),但需要额外的O(n)空间:
python复制def majorityElement(nums):
counts = {}
for num in nums:
counts[num] = counts.get(num, 0) + 1
if counts[num] > len(nums)//2:
return num
这种方法在实际工程中很实用,特别是当数据规模不大时。它的优势在于:
如果将数组排序,多数元素必定位于数组中间位置:
python复制def majorityElement(nums):
nums.sort()
return nums[len(nums)//2]
这个方法虽然时间复杂度较高,但实现极其简单,在数据量不大时是个不错的选择。它背后的数学原理是:多数元素占比超过50%,所以排序后必然占据中间位置。
这是最优美的解法,只需要O(1)的额外空间:
python复制def majorityElement(nums):
count = 0
candidate = None
for num in nums:
if count == 0:
candidate = num
count += (1 if num == candidate else -1)
return candidate
摩尔投票法的核心思想是"正负抵消":
实战技巧:在面试中解释这个算法时,可以用现实中的投票场景类比,帮助面试官理解这个抽象的过程。
| 算法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 暴力解法 | O(n²) | O(1) | 仅用于教学演示 |
| 哈希表 | O(n) | O(n) | 通用场景 |
| 排序法 | O(nlogn) | O(1)或O(n) | 数据量较小 |
| 摩尔投票法 | O(n) | O(1) | 最优解,面试首选 |
在实际编码时需要考虑:
python复制# 增强鲁棒性的实现
def majorityElement(nums):
if not nums:
raise ValueError("Input array cannot be empty")
count = 0
candidate = None
for num in nums:
if count == 0:
candidate = num
count += (1 if num == candidate else -1)
# 验证是否真的是多数元素(题目保证存在可省略)
if nums.count(candidate) > len(nums)//2:
return candidate
else:
raise ValueError("No majority element exists")
多数元素算法在现实中有广泛应用:
常见的变种问题包括:
对于n/3问题,可以扩展摩尔投票法:
python复制def majorityElement(nums):
if not nums:
return []
# 初始化两个候选人和计数器
count1, count2 = 0, 0
candidate1, candidate2 = None, None
for num in nums:
if num == candidate1:
count1 += 1
elif num == candidate2:
count2 += 1
elif count1 == 0:
candidate1 = num
count1 = 1
elif count2 == 0:
candidate2 = num
count2 = 1
else:
count1 -= 1
count2 -= 1
# 验证阶段
result = []
for c in [candidate1, candidate2]:
if nums.count(c) > len(nums)//3:
result.append(c)
return result
这个变种展示了摩尔投票法的强大扩展性。在准备面试时,建议不仅要掌握基础解法,还要理解算法背后的思想,这样才能灵活应对各种变种问题。