求n个数中出现次数超过的元素。
Moore's majority vote algorithm可以在O(n)时间内求解问题。算法流程如下:
维护一个计数器和当前候选元素,对数组进行扫描。若计数器为0,将当前元素作为候选元素。若当前元素等于候选元素,则计数器加一,否则减一。扫描完毕时候选元素即为所求,再扫描一次数组统计候选元素个数,若超过则为所求。代码如下:
int majorityElement(vector<int>& nums) {
int candidate, counter = 0, len = nums.size();
for(int i = 0; i < len; ++i){
if(counter == 0)
candidate = nums[i];
if(nums[i] == candidate)
++ counter;
else
--counter;
}
return candidate;
}
简单证明如下:循环内candidate代表当前票数最高的元素,遇到与candidate值相同的元素,counter加一,否则减一,当且仅当candidate元素超过时,counter才不会被抵消为0。
方法二:位操作
对每一个bit统计该bit在数组元素中出现的次数,若大于,则在majority element中该bit定为1。
反证:若存在某一位,在数组中出现超过次,而在majority element该bit为0。由于majority element中该bit为0,所以该bit中0的个数大于,则1的个数不超过,与假设矛盾。代码如下:
int majorityElement(vector<int>& nums) {
int cnt[32], len = nums.size(), limit = len / 2;
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < 32; ++i){
int val = 1 << i;
for(int j = 0; j < len; ++j)
if(nums[j] & val)
++cnt[i];
}
int ans = 0;
for(int i = 0; i < 32; ++i){
if(cnt[i] > limit)
ans += 1 << i;
}
return ans;
}
变形:求n个数中出现次数超过的元素。
由于次数超过的元素个数不超过两个,所以可以保存当前top2的候选者,counter为0时将该元素作为候选,碰到其他元素,则二者的counter均减一,由于剩下的元素个数小于,所以无法将解的counter抵消成0。要注意的细节是:要先将当前元素与两个候选者进行比较,对counter作相应增加,都不匹配时才能对counter为0的候选者进行重置,这是为了保证两个候选者为不同的元素。代码如下:
vector<int> majorityElement(vector<int>& nums) {
int c1 = INT_MIN, c2 = INT_MIN, counter1 = 0, counter2 = 0;
int n = nums.size();
for(int i = 0; i < n; ++i){
if(nums[i] == c1)
++counter1;
else if(nums[i] == c2)
++counter2;
else if(counter1 == 0)
c1 = nums[i], counter1 = 1;
else if(counter2 == 0)
c2 = nums[i], counter2 = 1;
else
--counter1, --counter2;
}
counter1 = 0, counter2 = 0;
for(int i = 0; i < n; ++i){
if(nums[i] == c1)
++counter1;
else if(nums[i] == c2)
++counter2;
}
vector<int> ans;
if(counter1 > n / 3)
ans.push_back(c1);
if(counter2 > n / 3)
ans.push_back(c2);
return ans;
}