LeetCode 169. 多数元素
问题描述
给定一个大小为 n
的数组,找到其中的多数元素。多数元素指在数组中出现次数 大于 ⌊n/2⌋
的元素。假设数组非空,且总是存在多数元素。
示例:
输入: [3,2,3]
输出: 3
输入: [2,2,1,1,1,2,2]
输出: 2
算法思路
方法一:摩尔投票法(最优解)
- 核心思想:多数元素与其他元素两两抵消后,剩余元素必为多数元素
- 步骤:
- 初始化候选元素
candidate
和计数器count = 0
- 遍历数组:
- 当
count == 0
时,设置当前元素为候选元素 - 当元素等于候选元素时,
count++
- 否则
count--
- 当
- 初始化候选元素
- 结果:最终候选元素即为多数元素
方法二:排序法
- 核心思想:排序后中间位置必为多数元素
- 步骤:
- 将数组排序
- 返回中间位置元素
nums[n/2]
代码实现
方法一:摩尔投票法
class Solution {
public int majorityElement(int[] nums) {
int candidate = 0;
int count = 0;
for (int num : nums) {
if (count == 0) {
candidate = num; // 设置新候选
}
// 更新计数器
count += (num == candidate) ? 1 : -1;
}
return candidate; // 最终候选即为多数元素
}
}
方法二:排序法
import java.util.Arrays;
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2]; // 中间位置必为多数元素
}
}
算法分析
- 时间复杂度:
- 摩尔投票法:O(n)(单次遍历)
- 排序法:O(n log n)(排序时间复杂度)
- 空间复杂度:
- 摩尔投票法:O(1)(常数空间)
- 排序法:O(1) 或 O(n)(取决于排序算法)
算法过程
输入 nums = [2,2,1,1,1,2,2]
:
步骤 元素 候选(candidate) 计数器(count)
1 2 2 (初始化) 1
2 2 2 2
3 1 2 1
4 1 2 0 → 重置候选
5 1 1 (新候选) 1
6 2 1 0 → 重置候选
7 2 2 (新候选) 1
结果:candidate = 2
测试用例
public static void main(String[] args) {
Solution solution = new Solution();
// 测试用例1:标准示例
int[] nums1 = {3,2,3};
System.out.println("Test 1: " + solution.majorityElement(nums1)); // 3
// 测试用例2:多数元素在末尾
int[] nums2 = {2,2,1,1,1,2,2};
System.out.println("Test 2: " + solution.majorityElement(nums2)); // 2
// 测试用例3:单一元素
int[] nums3 = {5};
System.out.println("Test 3: " + solution.majorityElement(nums3)); // 5
// 测试用例4:多数元素连续出现
int[] nums4 = {1,1,1,2,3};
System.out.println("Test 4: " + solution.majorityElement(nums4)); // 1
// 测试用例5:多数元素交替出现
int[] nums5 = {4,5,4,5,4};
System.out.println("Test 5: " + solution.majorityElement(nums5)); // 4
}
关键点
-
摩尔投票法原理:
- 多数元素数量 > n/2
- 每次抵消操作相当于移除两个不同元素
- 最终剩余元素必为多数元素
-
重置候选条件:
- 当计数器归零时,表示之前的所有元素已完成抵消
- 此时从当前位置开始新一轮统计
-
算法正确性保证:
- 题目假设数组非空且存在多数元素
- 无需验证最终结果的正确性
常见问题
1. 为什么摩尔投票法不验证结果?
题目明确说明数组中总是存在多数元素,因此最终候选元素必定正确。
2. 处理不存在多数元素的情况?
若题目不保证存在多数元素,需增加验证步骤:
int verify = 0;
for (int num : nums) {
if (num == candidate) verify++;
}
return (verify > nums.length/2) ? candidate : -1;
3. 为什么排序法返回中间元素?
多数元素数量超过一半,排序后中间位置(n/2)必被其占据。
4. 最坏情况举例:
摩尔投票法:所有其他元素先出现(如 [1,2,3,4,5,5,5]
),但最终仍会收敛到多数元素。
5. 空间复杂度对比:
摩尔投票法(O(1))优于哈希表法(O(n)),是最优解。