Leetcode #169 Majority Element

来源:互联网 发布:淘宝退款多久自动处理 编辑:程序博客网 时间:2024/04/29 05:17

Source: https://leetcode.com/problems/majority-element/

169.Majority Element

Given an array (nums) of size n,find the majority element. The majority element is the element that appears morethan  n/2  times.

Youmay assume that the array is non-empty and the majority element always exist inthe array.

 

Solution:

       依题意,给的样例中,这样的Majority Element总是存在的,所以不需要对其他情况进行考虑。那么,不怎么需要思考可以想到一个时间复杂度为O(n2)的做法,即用一个ele数组记录其中出现过的元素,另用一个count数组记录ele数组中对应元素出现的次数。之后,从头遍历整个nums数组,对于每一个nums数组中的元素,和ele数组中出现过的元素作比较。如果ele数组中有一致的记录,则将count数组中对应的记录数值加1;否则在ele数组与count数组中增加对这一元素的记录。最后,用O(n)的时间找出count数组的最大值,这个最大值对应的ele数组中的元素即所求的Majority Element。提交代码如下,可以通过:

 

class Solution {public:    int majorityElement(vector<int>& nums) {        vector<int> ele;        vector<int> count;        int i,j;        bool rpt;                ele.push_back(nums[0]);        count.push_back(1);        for (i=1;i<nums.size();i++)        {        rpt=0;for (j=0;j<ele.size();j++)        {        if (ele[j]==nums[i])        {        rpt=1;count[j]++;        break;}}if (rpt==0){ele.push_back(nums[i]);count.push_back(1);}}int ansId=0;for (i=1;i<count.size();i++){if (count[i]>count[ansId])ansId=i;}return ele[ansId];    }};

       此外,鉴于这道题是出现在分治策略中的题目,也可以用分治的思路解决这个问题。这一基本思路为,将整个nums数组等分为两个数组,然后比较两个数组的Majority Element。如果两个数组的Majority Element一致,无疑它们就是所求的Majority Element,否则比较nums数组中这两个元素出现过的次数即可,这一过程的时间复杂度是O(n)。运行时间的递归公式为T(n)=2T([n/2])+O(n),由Master theorem可知,T(n)=O(nlogn)。提交代码如下,可以通过:

(不过个人对分之策略的运用还不够熟练,代码比较混乱,通过时间也不如上一种做法)

class Solution {public:    int majorityElement(vector<int>& nums) {        if (nums.size()>3)        {        int i,temp=nums.size()/2+1;vector<int> formerHalf,latterHalf;formerHalf.insert(formerHalf.begin(),nums.begin(),nums.begin()+temp);latterHalf.insert(latterHalf.begin(),nums.begin()+temp,nums.end());int a=majorityElement(formerHalf),b=majorityElement(latterHalf);if (a==b)return a;else{int countA=0,countB=0;for (i=0;i<nums.size();i++){if (nums[i]==a)countA++;else if (nums[i]==b)countB++;}    if (countA>countB)    return a;    else if (countA<countB)    return b;    else    return 0;}}else if (nums.size()==1)return nums[0];else if (nums.size()==2){if (nums[0]==nums[1])return nums[0];elsereturn 0;}else{if (nums[0]==nums[1])return nums[0];else if (nums[2]==nums[0])return nums[0];else if (nums[2]==nums[1])return nums[1];elsereturn 0;}    }};

       最后是一种时间复杂度为O(n)的做法,代码比较简洁,空间复杂度为O(1)。这种做法是我从网上学到的Boyer–Moore majority vote algorithm,有一定通用性。具体而言,这种算法需要从头遍历整个数组,并记录遍历到当前位置出现的Majority Element。假定nums数组中第一个元素为a,用一个count变量追踪这一MajorityElement,ans为返回的结果。将ans和count分别初始化为a与1。之后,当count不为0时,对于nums中的每一个元素,如果其与当前的ans一致,那么count值加1,否则count值减1。如果当前count为0,那么nums中的下一个元素即为下一个有效的ans。最后,当nums遍历结束后,得到的ans即为nums的MajorityElement。这种做法的正确性的简单证明如下(不严谨但希望有助于理解):

       假定a为当前的ans值,count值大于0。如果nums中下一个元素也为a,那么count值加1,到目前为止支持a为Majority Element的选票多了1票;否则,count值减1,相当于目前为止支持a为Majority Element的选票少了1票。最后,Majority Element的count值必然是大于0的,因为题目保证了Majority Element的存在,而Majority Element是出现次数多于⌊ n/2 ⌋的元素。这种做法看似抹杀了a的下一个元素(如果它不是a的话)被选举的权利,但是,如果a的下一个元素不是a的话(假定为b)且恰好令count变为0,那么到此为止,a、b肯定不是MajorityElement,因为有和a的个数一样多的别的元素在,所以a不可能是,而极端情况是到此为止所以和a不一样的别的元素都是b,那么b也不可能是。那么。b要做的便是,待a的选票降为0时而此时正轮到它的时候,再上台参加选举,接受他人的投票。

那么对于aabcb的组合,结果将返回b,答案不是错了吗。的确错了,因为这种做法只能保证最后的ans值为有可能成为MajorityElement的元素,但这一数组并没有MajorityElement存在。在题目没有进一步说明的情况下(详见Leetcode#229, Majority Element II),应该再计算ans值在题目中出现的次数,看其是否确实大于⌊ n/2 ⌋,进一步确定这个唯一可能是MajorityElement的元素是否确实是。但题目明确保证了MajorityElement的存在,所以省去了这一步骤。代码如下,运行时间较第一、二种做法都要快。


class Solution {public:    int majorityElement(vector<int>& nums) {        int ans=nums[0];        int count=1;        int len=nums.size();        for (int i=1;i<len;i++)        {        if (count==0)        {        ans=nums[i];        count=1;}else{if (ans==nums[i])count++;elsecount--;}}return ans;    }};

0 0