给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:nums = [3,2,3]
输出:3
示例 2:
输入:nums = [2,2,1,1,1,2,2]
输出:2
提示:
n == nums.length
1 <= n <= 5 * 104
-109 <= nums[i] <= 109
进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
为了解决这个问题,我们可以使用一种称为“摩尔投票算法”(Boyer-Moore Voting Algorithm)的高效算法。这个算法在时间复杂度为O(n)且空间复杂度为O(1)的条件下解决了这个问题。
摩尔投票算法的基本思想
- 维护一个候选多数元素
candidate和一个计数器count。初始时,candidate可以为任意值,count为0。 - 遍历数组
nums中的每个元素x:- 如果
count为0,我们将candidate设置为x,即认为当前元素可能是多数元素。 - 如果
x等于candidate,则将count加1。 - 如果
x不等于candidate,则将count减1。
- 如果
- 遍历完成后,
candidate即为整个数组的多数元素。
算法的正确性
由于多数元素在数组中出现的次数大于n/2,那么在遍历过程中,candidate最终一定会被设置为多数元素。因为每当count减到0时,意味着到目前为止,没有任何元素可以成为多数元素。此时,可以将candidate设置为当前元素,并开始重新计数。由于多数元素的数量超过了数组长度的一半,所以candidate最终一定会是多数元素。
Java实现
public class Solution {
public int majorityElement(int[] nums) {
int count = 0;
Integer candidate = null;
for (int num : nums) {
if (count == 0) {
candidate = num;
}
count += (num == candidate) ? 1 : -1;
}
return candidate;
}
}
复杂度分析
- 时间复杂度:O(n),其中n是数组
nums的长度。我们只需要遍历数组nums一次。 - 空间复杂度:O(1),我们只需要常数空间存放
candidate和count。
为什么这个算法有效?
每当count变为0时,就更换candidate。这意味着到目前为止,之前的所有元素中,没有任何元素的出现次数能够超过数组长度的一半。因此,可以放弃这些元素,从当前元素重新开始计数。
由于多数元素的出现次数大于n/2,即使它在数组的前半部分被抵消,剩余的部分中它仍然是出现次数最多的元素。因此,最后candidate变量中存储的元素,就是整个数组的多数元素。
这个算法的巧妙之处在于,它利用了多数元素出现次数超过总数一半的特性,通过一次遍历就能找到这个元素,而且只用了O(1)的额外空间。
本文介绍了如何使用摩尔投票算法在O(n)时间和O(1)空间复杂度内解决LeetCode中的多数元素问题。通过遍历数组,动态更新候选多数元素并计数,最终找到出现次数超过n/2的元素。文章提供了算法的正确性证明、Java实现及复杂度分析。
1066

被折叠的 条评论
为什么被折叠?



