数学——众数¶
众数是一组数中出现频率最多的数,可以用unordered_map
来统计从而求得答案,但是对于一个特殊的序列,众数的出现次数大于n/2
,解决方法就会比较多了。
题面以LeetCode 169.Majority Element为背景:
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋
times.
You may assume that the array is non-empty and the majority element always exist in the array.
Example 1:
Input: [3,2,3]
Output: 3
Example 2:
Input: [2,2,1,1,1,2,2]
Output: 2
排序法¶
排序的方法类似于求中位数的方法,因为出现次数最多的元素的数量大于n/2
,所以排序后下标为n/2
的一定就是众数。
class Solution {
public:
int majorityElement(vector<int>& nums) {
std::ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
sort(nums.begin(), nums.end());
int n = nums.size();
return nums[n / 2];
}
};
摩尔投票法¶
这种方法还是第一次遇到,但是有一个大前提就是众数的出现次数至少是n/2
,叫做摩尔投票法(Moore Voting),核心思路是每次让两个不同的元素抵消掉,那么最后剩下的就是众数了,直观上比较好理解。在写算法的时候,可以不用真的删掉元素,而是用一个sign
值来标记,如果是两个不同的元素,那么数值减1,当减到0的时候,让res
为当前元素,标记sign
增加1.
class Solution {
public:
int majorityElement(vector<int>& nums) {
std::ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int sign = 0;
int res = 0;
int n = nums.size();
for (int i = 0; i < n; ++i) {
if (sign == 0) {
res = nums[i];
++sign;
}
else {
if (nums[i] == res) ++sign;
else --sign;
}
}
return res;
}
};
位运算法¶
位运算的方法思路比较新奇,因为考虑到最后的结果是一个int
类型的数,所以转而去检验每一位的1的个数,如果1的个数超过了n/2
,那么这一位一定是1。
class Solution {
public:
int majorityElement(vector<int>& nums) {
std::ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int res = 0;
int n = nums.size();
for (int i = 0; i < 32; ++i) {
int one = 0, zero = 0;
for (auto num : nums) {
if (one > n / 2 || zero > n / 2) break;
if (num & (1 << i)) ++one;
else ++zero;
}
if (one > zero) res |= (1 << i);
}
return res;
}
};