首页 > 代码库 > 229. Majority Element II

229. 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 time and in O(1) space.

第一回合

一个序列中符合上述条件的元素个数可能有0,1,2三种情况。由于限定时间复杂度为O(n),空间复杂度为O(1),几乎就只有nth_element一条路可以走。

首先找出排序位置为n/3的元素,然后沿着该元素的前后遍历这个元素的相等值。如果前后跨度超过n/3,则该元素为符合要求的结果。

然后对剩下的序列进行同样的操作,寻找是否有符合要求的元素。

讲过很长时间的编码,发现无法有效实现上述算法。

第二回合

经过参考其他答案,改用Majority Element中使用过的摩尔投票法。

所谓摩尔投票法的基本思想是:我们可以遍历数组,当碰到两个不一样的数字时,我们将这两个数字同时丢弃这两个数字中可能有一个为 Majority Element,也可能两个都不为Majority Element。因为k 大于 n/2,所以在最差情况下(每次移除不同数字时都包含一个Majority Element),我们仍然能够保证最后得到的数字是Majority Element。这是对于个数超过n/2的元素而言。

对于个数超过n/3的元素而言,可以设定两个候选者,我们需要找到三个不同的数字,然后抛弃掉这三个数字:
首先要判断是否等于candidate,如果等于candidate那么对应的 candidate 必须加一等待其他的数字来消除它
当有一个 candidate 的 count 为 0 时,说明该 candidate 已经全部被消除,我们需要设定新的 candidate 数字。
当一个数字不等于两个 candidate,同时两个 candidate 的 count 都不为零。这意味着当前这个数字就是这两个 candidate 等待的第三个数字。于是这三个数字被移除,同时他们的 count 都要减一。

最后,还要在遍历一遍序列,验证所得的候选值是否符合要求。

实话实说,这个题目只能凭肌肉记忆。

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
    int cnt1 = 0, cnt2 = 0, a=0, b=1;
    
    for(auto n: nums){
        if (a==n){
            cnt1++;
        }
        else if (b==n){
            cnt2++;
        }
        else if (cnt1==0){
            a = n;
            cnt1 = 1;
        }
        else if (cnt2 == 0){
            b = n;
            cnt2 = 1;
        }
        else{
            cnt1--;
            cnt2--;
        }
    }
    
    cnt1 = cnt2 = 0;
    for(auto n: nums){
        if (n==a)   cnt1++;
        else if (n==b)  cnt2++;
    }
    
    vector<int> res;
    if (cnt1 > nums.size()/3)   res.push_back(a);
    if (cnt2 > nums.size()/3)   res.push_back(b);
    return res;
}
};

 

229. Majority Element II