Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋
times.
You may assume that the array is non-empty and the majority element always exist in the array.
Example 1:
Input: [3,2,3] Output: 3
Example 2:
Input: [2,2,1,1,1,2,2] Output: 2
非常简洁的题目, 找到出现次数最多的数字。
但是我没想到的是,官方竟然给出了6种各不相同的解法,献上我的膝盖~还是我太年轻了。
有不同的思路当然不能错过,说不定哪一天在这道题上增加一些条件之后,那种解法就是最优解了呢。
1.暴力求解
逐个对数组中每个元素计算个数,直接上代码可能更清晰一点:
for (int elem : nums) {
int nowCount = 0;
for (int nElem : nums) {
if (elem == nElem) {
++nowCount;
}
}
if (nowCount > numLen / 2) {
return elem;
}
}
虽然这种做法可以AC,但是算法复杂度极高。
2.hash映射(暴力解法的优化)
我们可以看到,在暴力解法中,对于重复的数字进行了多次计数,最简单的优化策略就是使用HashMap记录数字对应的出现次数,这样一次遍历就可以完成。实现的代码也不难理解:
for (int i = 0; i < numLen; ++i) {
if (intCount.containsKey(nums[i])) {
intCount.put(nums[i], intCount.get(nums[i]) + 1);
} else {
intCount.put(nums[i], 1);
}
}
遍历完成之后,再遍历一遍HashMap找到数字最大的即可。但是提交后的代码表现不是很好,因为HashMap的一些内部操作也会浪费大量的时间。但是理论的时间复杂度只在O(N)。
3.排序法
排序这个方向我是思考过的,但是想到可以使用hash映射在O(N)的时间复杂度内解决,就没有继续思考下去,意想不到的是,排序这个方向的思路竟然这么简洁。首先我们可以知道的是数组中出现次数最多的元素,其出现次数必然比 N / 2 要大,我们是不是可以这么认为,排序之后的数组,在nums[nums.length / 2] 的位置上的元素必然是出现次数最多的元素。如下图所示:
无论是数组是奇数长度,还是偶数长度,在 nums[nums.length / 2] 处都是我们要的结果(注意现在的所说的除法都是按照整数除法来计算)。
代码简洁到了可以直接在这里放完整代码了:
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2];
}
}
提交后的结果达到了一个非常理想的时间,但是理论上的时间复杂度是O(),要比方法二的速度慢,但是实际结果却相反,并且Java的sort函数使用的是dual-pivot quick sort针对硬件层面也有了一定的优化,再加上HashMap操作也需要时间,更加大了两者的差距,反倒最后
倍的差距倒是不明显了。
4.随机查找法
5.分治法
6.博伊尔-摩尔投票算法
boyer-moore算法主要的用途就是在线性的时间和空间内,找到元素序列中包含最多的元素。
在本题的应用中,定义一个候选人变量candidate(用来记录扫描至当前位置时,可能的出现次数最多的元素),一个计数变量count,初始化都为0,然后开始循环;每次循环时检查count是否为0,记录当前元素为candidate,并检查当前元素与candidate是否相同,若相同则count + 1,若不同则count - 1。具体循环体如下:
for (int elem : nums) {
if (count == 0) {
candidate = elem;
}
count += elem == candidate ? 1 : -1;
}
整个过程与投票的过程非常相似,个数最多的元素就是最后的candidate值,这样的应用是有前提的,那就是保证有一个元素出现的次数大于 N / 2。
算法的理论时间复杂度为O(N),空间复杂度为常数,是这道题的最佳选择。
Boyer-Moore投票算法:
class Solution {
public int majorityElement(int[] nums) {
int count = 0;
int candidate = 0;
for (int elem : nums) {
if (count == 0) {
candidate = elem;
}
count += elem == candidate ? 1 : -1;
}
return candidate;
}
}
如有错误,欢迎指摘。也欢迎通过左上角的“向TA提问”按钮问我问题,我将竭力解答你的疑惑。