LeetCode169—MajorityElements

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,当然时间复杂度也是线性的。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值