求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; }