链接: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;
}
};