Leetcode #169 Majority Element

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];
			else
				return 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];
			else
				return 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++;
				else
					count--;
			}
		}
		return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值