LeetCode 169. Majority Element(Boyer-Moore Voting)

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

思路

Approach 1: 迭代nums,用map记录各值出现的次数,再迭代map,次数大于size/2的即majority element。
Approach 2: Boyer-Moore Voting。基本原理:假设某混合物中,某物质M含量p1,从中分离出一部分,离开部分M的含量p2 < p1,那剩余部分M含量p3 > p1。majority element(简写major)是出现次数大于⌊ n/2 ⌋的元素,即此时大于1/2。迭代nums,选取一个候选A,计数cnt,表示已遇到 cnt+x 个 A,x 个非A。迭代到某元素B时,如果cnt不为0,若B等于A,cnt++;若不等于,cnt–。如果能保持cnt>0直到结束,那A肯定就是要找的major,因为A多于非A;如果到某步cnt=0,则弃掉此prefix,包括x个A,x个非A,以刚迭代到的B做候选,cnt=1,继续迭代(看做一个新的开始,已遇到1个A,0个非A)。因为此prefix中,任何元素含量都不超过1/2,所以major在截取后的部分含量上升,仍然是超出一半的。

类似题目229. Majority Element II,major是次数大于⌊ n/3 ⌋的元素。迭代nums,选取两个候选AB,计数cnta,cntb,表示已经遇到 cnta+x 个 A,cntb+x 个 B,x 个非AB。迭代到某元素C时,若C等于A,cnta++;若C等于B,cntb++;若两者都不等,如果两计数都大于0,则cnta–,cntb–。如果某计数等于0,假设是cntb=0,即已遇到 cnta+x 个 A,x 个 B,x 个非AB,此时可以把这长三个x的部分舍弃掉。Why? 因为这部分里,任何元素含量都不超过1/3,原来整体里的major,在剩下部分仍然是major。怎么舍弃呢?只要把C赋给B,cntb = 1即可,相当于新开始,已经遇到 cnta个A,1个B,0个非AB。到结束时要注意,两个候选不一定就是major,从黑体部分就可以看出来了,AB不一定多于1/3,不过可以确定非AB的元素一定不超过1/3。这时再迭代nums,计数AB。

代码

169

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        map<int, int> cnts;
        for(auto x : nums) {
            cnts[x]++;
        }
        for(auto &p : cnts) {
            if(p.second > nums.size() / 2) return p.first;
        }
        return 0;
    }
};
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int candidate, cnt = 0;
        for(auto x : nums) {
            if(cnt == 0) {
                candidate = x;
                cnt = 1;
            } else {
                cnt = x == candidate ? cnt + 1 : cnt - 1;
            }
        }
        return candidate;
    }
};

229

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        int A, B, cnta = 0, cntb = 0;
        for(auto x : nums) {
            if(x == A) {
                cnta++;
            } else if(x == B) {
                cntb++;
            } else if(cnta == 0) {
                A = x; cnta = 1;
            } else if(cntb == 0) {
                B = x; cntb = 1;
            } else {
                cnta--; cntb--;
            }
        }
        vector<int> res;
        if(cnta > 0) {
            cnta = 0;
            for(auto x : nums) {
                if(x == A) cnta++;if(x == B) cntb++;
            }
            if(cnta > nums.size() / 3) res.push_back(A);
        }
        if(cntb > 0) {
            cntb = 0;
            for(auto x : nums) {
                if(x == B) cntb++;
            }
            if(cntb > nums.size() / 3) res.push_back(B);
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值