LeetCode169—MajorityElements
原题
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.
在一个数组中找到出现次数大于n/2的“多数派”元素。
题目的前提是,一定存在这样的多数派元素,如果不存在的话也可以求出来。
西电计院的同学应该对这个题还有比较深刻的印象,就是算法考试中的,呵呵~
分析1
如果对时间复杂度没有要求的话,这个题目最简单的做法对元素先进行排序。
排序完的序列索引为n/2的元素肯定是出现次数超过半数的元素。
代码1
class Solution
{
public:
int majorityElement( vector<int>&nums );
};
int Solution::majorityElement( vector <int> &nums )
{
sort(nums.begin(),nums.end());//排序
int n = nums.size();
return nums[n/2];
}
分析2
std::sort()
的时间复杂度为
O(nlogn)
,当然也可以自己写一个线性时间复杂度内的counting-sort,但是感觉意义不大,虽然思想差不错,我们有更好的办法将时间复杂度控制在
O(n)
范围内,那就是直接用HashMap
了。
这样我们只需要两次线性扫描:
前提是建立一个hashmap,key为数组中的元素,value为他们出现的次数
第一次,统计每个元素的出现次数,map[key]=map[key]+1;
第二次,返回超过半数的key即可。
代码2
class Solution
{
typedef unordered_map<int,int>::iterator iterator;//迭代器类型
public:
int majorityElement( vector<int>&nums );
};
int Solution::majorityElement( vector<int> &nums )
{
unordered_map<int,int>myMap;
for(int i = 0 ; i < nums.size(); i++)
{
myMap[nums[i]]= myMap[nums[i]]+1;
}//统计
/* 1.要么直接访问
for(int i = 0 ; i < nums.size(); i++)
{
if(myMap[nums[i]] >= (nums.size()+1)/2)
return nums[i];
}
*/
//2.或者用迭代器访问
for( iterator it = myMap.begin();it!=myMap.end(); it++)
{
if( (*it).second >= (nums.size()+1)/2 )
return (*it).first;
}
return -1;//如果没有超过半数的元素
}
分析3
上述分析2
已经将时间复杂度控制在线性条件下了,但是空间复杂度增加,这是用空间换取时间的典型方法,接下来要介绍的算法就牛逼了,它的空间也能控制在
O(1)
条件下。
这个算法叫做:Boyer–Moore majority vote algorithm
其思想说明一下:
1.首先,假设一个数组[A A B C A D A E A],如果让人来做这件事请,我们会删去两两不同的元素(不管我们采取哪种组合,只要是两两不同即可),删到最后剩下的就是我们需要的元素。本例中即A
2.但是,对于计算机来说,它只能从头到尾对数组进行遍历,没有办法去挑两两不同的元素,为了模拟上述过程,我们定义一个count和一个表示当前可能成为“多数派”的元素candidate。
3.在一次扫描中,如果元素和当前candidate相同则count++,不同则count–,表示删除一对两两不同元素,当count减为0时,我们就需要更新我们的candidate了。
4.如果还要考虑不存在多数派的情况,最后还需要进行一点小处理。这部分在代码中说明
这个算法的发明者提供了一个算法的单步演示:演示链接
代码3
int Solution::majorityElement (vector<int> & nums)
{
int candidate = nums[0];
int count =0;
for(int i=0; i < nums.size(); i++ )
{
if(count == 0)//重新选择candidate
{
count = 1;
candidate = nums[i];
}
else
{
count = candidate==nums[i]?(count+1):(count-1);
}
}
//下面代码排除没有多数派情况
count = 0;
for (int i =0;i<nums.size(); i++)
{
if (nums[i] == candidate)
count++;
}
if (count < (nums.size() + 1) / 2)
return -1;
return candidate;
}
判断是否存在多数派的思想就是看最后的candidate的个数是否超过n/2,当然时间复杂度也是线性的。