多数元素
Majority Element
解
方法一:哈希表
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int, int>hash;
int max = 0, majority = 0;
for (int num : nums) {
hash[num]++;
if (hash[num] > max) {
majority = num;
max = hash[num];
}
}
return majority;
}
};
方法二:排序
将数组中的元素按照递增或者递减的顺序排序,在
⌊
n
2
⌋
\lfloor\frac{n}{2}\rfloor
⌊2n⌋的元素一定是众数。
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
};
方法三:随机数
我们随机挑选一个数,该数是众数的可能性是最大的,因此,我们每次取一个随机数进行验证。
class Solution {
public:
int majorityElement(vector<int>& nums) {
while (true) {
int candidate = nums[rand() % nums.size()];
int count = 0;
for (int num : nums) {
if (num == candidate) {
count++;
}
}
if (count > nums.size() / 2) {
return candidate;
}
}
return -1;
}
};
方法四:分治法
如果数a
是数组nums
的众数,如果我们将nums
分成两部分,那么a
必定是至少一部分的众数。
可以用反证法证明。
class Solution {
int count(vector<int>& nums, int target, int left, int right) {
int count = 0;
for (int i = left; i <= right; i++) {
if (nums[i] == target) {
count++;
}
}
return count;
}
int majorityElement_rec(vector<int>& nums, int left, int right) {
if (left == right) {
return nums[left];
}
int mid = (left + right) >> 1;
int left_majority = majorityElement_rec(nums, left, mid);
int right_majority = majorityElement_rec(nums, mid + 1, right);
if (count(nums, left_majority, left, right) > (right - left + 1) >> 1) {
return left_majority;
}
if (count(nums, right_majority, left, right) > (right - left + 1) >> 1) {
return right_majority;
}
return -1;
}
public:
int majorityElement(vector<int>& nums) {
return majorityElement_rec(nums, 0, nums.size() - 1);
}
};
方法五:Boyer-Moore 投票算法
博伊尔-摩尔投票算法证明:
假设众数是maj
- 如果候选人不是maj,那么maj会和其他非候选人反对候选人,由于maj的数量大于其他数之和,候选人一定会落选。
- 如果候选人是maj,他会给自己投支持票,到最后maj一定胜出。
class Solution {
public:
int majorityElement(vector<int>& nums) {
int candidate = 0;
int count = 0;
for (int num : nums) {
if (num == candidate) {
count++;
} else {
count--;
if (count < 0) {
candidate = num;
count = 1;
}
}
}
return candidate;
}
};
方法六:位运算
将所有数字转化成二进制,统计对应位的1的个数,众数中某一位所含1的个数若个数一定大于
⌊
n
2
⌋
\lfloor\frac{n}{2}\rfloor
⌊2n⌋,反之也成立。
充分性:众数个数大于
⌊
n
2
⌋
\lfloor\frac{n}{2}\rfloor
⌊2n⌋,充分性是显然的。
必要性,反证法:若小于
⌊
n
2
⌋
\lfloor\frac{n}{2}\rfloor
⌊2n⌋,则0的个数大于
⌊
n
2
⌋
\lfloor\frac{n}{2}\rfloor
⌊2n⌋,0来自于除众数以外的一些数,但我们显然可以知道,即使0来自于除众数以外的所有数,它的个数也不会大于
⌊
n
2
⌋
\lfloor\frac{n}{2}\rfloor
⌊2n⌋,得到矛盾。
class Solution {
public:
int majorityElement(vector<int>& nums) {
int ret = 0, n = nums.size() >> 1;
for (int i = 0; i < 32; i++) {
int count = 0;
for (int num : nums) {
count += num >> i & 1;
if (count > n) {
ret += 1 << i;
break;
}
}
}
return ret;
}
};