LeetCode 229. Majority Element II ,169. Majority Element

来源:互联网 发布:php 得到类型 编辑:程序博客网 时间:2024/05/21 07:54

题目链接:https://leetcode.com/problems/majority-element-ii/

题目描述:

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorithm should run in linear timeand inO(1)space.

Hint:

  1. How many majority elements could it possibly have?
  2. Do you have a better hint? Suggest it!
分析:一开始没有别的思路,先试着写,不考虑时间复杂度O(n)的要求,先将数组排序,然后统计看看有没有众数。时间复杂度不满足要求,但是也提交成功了。
class Solution {public:    vector<int> majorityElement(vector<int>& nums) {        vector<int> result;        int len=nums.size();        if(nums.empty()||len==1)            return nums;        //先排序        sort(nums.begin(),nums.end());        int count=1;        int cur=nums[0];        for(int i=1;i<len;i++)        {            if(count>len/3)//判断count有没有满足要求                result.push_back(cur);            if(nums[i]==cur)            {                count++;            }            else            {                count=1;                cur=nums[i];            }            if(count>len/3)//判断count有没有满足要求                result.push_back(cur);        }        result.erase(unique(result.begin(),result.end()),result.end());        return result;    }};
查到一个很高效的算法Moore's voting algorithm(多数投票法),先考虑这个问题: 从一个数组中找出出现半数以上的元素

算法的基本思想

每次都找出一对不同的元素,从数组中删掉,直到数组为空或只有一种元素。 不难证明,如果存在元素e出现频率超过半数,那么数组中最后剩下的就只有e。
当然,最后剩下的元素也可能并没有出现半数以上。比如说数组是[1, 2, 3],最后剩下的3显然只出现了1次,并不到半数。排除这种false positive情况的方法也很简单,只要保存下原始数组,最后扫描一遍验证一下就可以了。

算法的实现(转自http://blog.csdn.net/chfe007/article/details/42919017)

在算法执行过程中,我们使用常量空间实时记录一个候选元素c以及其出现次数f(c),c即为当前阶段出现次数超过半数的元素。

在遍历开始之前,该元素c为空,f(c)=0。

然后在遍历数组A时,如果f(c)为0,表示当前并没有候选元素,也就是说之前的遍历过程中并没有找到超过半数的元素。那么,如果超过半数的元素c存在,那么c在剩下的子数组中,出现次数也一定超过半数。因此我们可以将原始问题转化为它的子问题。此时c赋值为当前元素, 同时f(c)=1。

如果当前元素A[i] == c, 那么f(c) += 1。(没有找到不同元素,只需要把相同元素累计起来)

如果当前元素A[i] != c,那么f(c) -= 1。 (相当于删除1个c),不对A[i]做任何处理(相当于删除A[i])

如果遍历结束之后,f(c)不为0,那么元素c即为寻找的元素。上述算法的时间复杂度为O(n),而由于并不需要真的删除数组元素,我们也并不需要额外的空间来保存原始数组,空间复杂度为O(1)。

本算法的链接:http://www.cs.utexas.edu/~moore/best-ideas/mjrty/index.html

注意:当根本不存在众数时,最后剩下的不一定是频率最高的

代码:

int majorityElement(vector<int> &num){    int curIdx = 0, count = 1;    for (int i = 1; i < num.size(); ++i)    {        num[i] == num[curIdx] ? ++count : --count;        if (!count)        {            curIdx = i;            count = 1;        }    }    return num[curIdx];}
回到本问题上来,

  首先,可以通过分析得到结论:满足条件的数字个数cnt最多为2。 
  证明: ifcnt>2cnt× (n/3+1 )>n 超出原数组的大小。 
  然后,借鉴在数组中求出现次数超过一半的数这道题的思路: 

即:

记变量n1, n2为候选众数; c1, c2为它们对应的出现次数

遍历数组,记当前数字为num

若num与n1或n2相同,则将其对应的出现次数加1

否则,若c1或c2为0,则将其置为1,对应的候选众数置为num

否则,将c1与c2分别减1

最后,再统计一次候选众数在数组中出现的次数,若满足要求,则返回之。

代码:

class Solution {public:    vector<int> majorityElement(vector<int>& nums) {        vector<int> result;        int len=nums.size();        if(nums.empty()||len==1)            return nums;                    int n1=0,n2=0;        int c1=0,c2=0;        //第一遍扫描找出两个备选的        for(int i=0;i<len;i++)        {            if(nums[i]==n1)                c1++;            else if(nums[i]==n2)                 c2++;            else if(c1==0)            {                n1=nums[i];                c1=1;            }            else if(c2==0)            {                n2=nums[i];                c2=1;            }            else             {                c1--;c2--;            }        }        //第二遍扫描,统计这两个备选数出现的次数        c1=0;c2=0;        for(int i=0;i<len;i++)        {            if(nums[i]==n1)                c1++;            else if(nums[i]==n2)                c2++;        }        //判断这两个备选的是否满足要求,满足就存储        if(c1>len/3)            result.push_back(n1);        if(c2>len/3)            result.push_back(n2);        return result;    }}; 


注意:以下代码,有的测试用例通不过,如{1,2,2,3,2,1,1,3},判断的顺序不能反


class Solution {public:    vector<int> majorityElement(vector<int>& nums) {        vector<int> re;        if(nums.size() ==0) return re;        if(nums.size() == 1) return nums;        int i,num1,num2,cnt1=0,cnt2=0;        //找出出现频率最高的两个数        for(i = 0; i < nums.size(); i++)        {            if(cnt1 == 0 || num1 == nums[i])            {                num1 = nums[i];                cnt1++;            }            else if(cnt2 == 0 || num2 == nums[i])            {                num2 = nums[i];                cnt2++;            }            else                cnt1--,cnt2--;        }        //统计两个数出现的次数        cnt1 = 0; cnt2 = 0;        for(i = 0; i < nums.size(); i++)        {            if(nums[i] == num1) cnt1++;            else if(nums[i] == num2) cnt2++;        }        //推断是否否何要求        if(cnt1 > nums.size()/3)            re.push_back(num1);        if(cnt2 > nums.size()/3)            re.push_back(num2);        return re;    }};




0 0