给定一个数组,求出其中出现次数大于n/2的数字;
暴力方法:
先排序,直接返回第i+n/2个元素;由于排序的时间复杂度为O(n*logn),这种方法不是最优的;
方法一:
暴力法中对所有的元素进行排序,其实这是没有必要的,我们只需要保证第n/2大元素处于第n/2位置就可以,其他元素的顺序没有要求;
可以直接利用STL里的nth_element()
函数,该函数的的实现主要利用快排里的轴点选取方法,可以自己实现一边;
void nth_element( RandomIt first, RandomIt nth, RandomIt last );
nth_element 是部分排序算法,它重排 [first, last) 中元素,使得:
1. nth 所指向的元素被更改为假如 [first, last) 已排序则该位置会出现的元素。
2. 这个新的 nth 元素前的所有元素小于或等于新的 nth 元素后的所有元素
代码如下:
class Solution {
public:
int majorityElement(vector<int>& nums) {
nth_element(nums.begin(),nums.begin()+nums.size()/2,nums.end());
return *(nums.begin()+nums.size()/2);
}
};
方法二:
利用摩尔投票法(第一次听说,思想还是比较易懂的)
最基本的摩尔投票问题,找出一组数字序列中出现次数大于总数1/2的数字(并且假设这个数字一定存在),显然这个数字只可能有一个。
摩尔投票算法是基于这个事实:每次从序列里选择两个不相同的数字删除掉(或称为“抵消”),最后剩下一个数字或几个相同的数字,就是出现次数大于总数一半的那个。
实现代码:
class Solution {
public:
int majorityElement(vector<int>& nums) {
int cnt=0,res=0;
for(auto &c:nums)
{
if(cnt==0)
{
res=c;
++cnt;
}
else if(res==c)
++cnt;
else
--cnt;
}
return res;
}
};
方法三
首先扫描一边数组,利用哈希表保存每个元素出现的次数;然后扫描哈希表找到出现次数最多的元素;
代码实现:
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int,int>ma;
for(auto &c:nums)
{
if(ma.count(c))
++ma[c];
else ma[c]=1;
}
for(auto &c:ma)
{
if(c.second>nums.size()/2)return c.first;
}
return -1;
}
};