一、题目描述
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。
进阶:
尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
二、基础题解
首先,既然标注为简单题了,说明肯定可以在短时间内得出解法,并且可以通过所有测试数据,只不过性能不会很好。
因为刷题用c++比较多一些,STL自然就是是标配了。所以本题第一时间想到的解法就是:
使用map
1、首先遍历一遍数组,使用map统计数组中每个元素及其出现的次数;
2、遍历map,找到出现次数最多的那个元素,即多数元素。
性能分析
时间复杂度:O(nlgn)
说明:因为每次修改元素的出现次数时,都需要修改map,而map是用红黑树实现的,根据红黑树的特性,修改树节点的时间复杂度是O(lgn)。总共有n个元素,所以中的时间复杂度是O(nlgn)。
空间复杂度:O(n)
说明:因为多数元素大于总数的一半,所以map大小的上限就是总数的一半(准确来说是总数一半取上整),即n/2。
三、进阶题解
上述题解其实并未用到“ 出现次数大于⌊ n/2 ⌋ ”性质,相当于就是求众数了。而接下来的解法会让人欣喜若狂!(可能像我这样的菜鸡才会这样吧233)
维护一个候选多数元素more及其出现次数 count。
1、初始化:more = 任意值,count = 0;
2、遍历数组 nums:
2.1 如果count 的值为 0,more = x ;
2.2 否则将x和more作比较:
2.2.1 如果 x == more,则count 加 1;
2.2.1 如果 x ! = more,则count 减 1;3、遍历完成后,more就是数组中的多数元素。
解析
我的理解是,因为已知多数元素出现的次数是一定大于⌊ n/2 ⌋的,所以对count执行+1操作其实就是记录多数元素的个数;而执行-1操作就是记录其他无关元素的个数。如果两者数量相等,那么count值最后一定等于0,但是因为多数元素数量更多,所以最后的count一定大于0,而对应的当前记录的数字more,就是这个多数元素!
性能分析
时间复杂度:O(n)
说明:只需遍历一次数组即可。
空间复杂度:O(1)
说明:只需维护两个整型变量,所以是常数空间。
四、总结
进阶解法利用了出现次数大于⌊ n/2 ⌋的性质,其性能就实现了质的飞跃,真是太美妙了!
不禁让我联想起电视剧上相似的场景:某个镜头中,某个人物的眼神特写,最后一定会暗示着什么~~~
五、代码
最后的最后,附上解题代码(c++),相信正在看的你们,一定能自己写出来的。
#include <bits/stdc++.h>
using namespace std;
int majorityElement(vector<int>& nums) {
int count = 0;
int more = 0;
for (int num : nums) {
if(count == 0){
more = num;
count++;
}else if(more == num){
count++;
}else{
count--;
}
}
return more;
}
int main() {
vector<int> test = {
1,2,2,1,3,3,1,1,1};
cout<<majorityElement(test)<<endl;
return 0;
}