首页 > 代码库 > 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