数组中出现次数超过一半的数字
题目描述:
一道简单难度的数组题,但面试要求空间复杂度一般为O(1)
解题思路:
1.排序
2.摩尔投票
3.哈希表
4.随机数法
5.位运算
1.排序
算法思路:将所给数组进行排序,取中位数,即为众数,众数出现频率一定大于数组大小的一半
代码实现:
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
};
2.摩尔投票
算法思路:可以理解为消消乐,众数为正,非众数为负数,我一票众数加1,你一票不是众数减1,最后两败俱伤,幸存的都是众数,因为众数人多hhh。
代码实现:
class Solution {
public:
int majorityElement(vector<int>& nums) {
//计分
int count = 0;
//众数
int canadite = 0;
for(int i = 0; i < nums.size(); i++){
//首先,没有人投票,选第一个作为众数
if(count == 0) canadite = nums[i];
//和众数相等 票数加1
if(nums[i] == canadite) count++;
//非众数 票数减1
else count--;
//最后票数大于数组元素个数一半 返回众数
if(count>nums.size()/2) return canadite;
}
return canadite;
}
};
3.哈希表
算法思路:不建议这种方法,空间需要O(N),简而言之就是我们使用哈希表来存储每个元素以及出现的次数。对于哈希映射中的每个键值对,键表示一个元素,值表示该元素出现的次数。
我们用一个循环遍历数组 nums 并将数组中的每个元素加入哈希映射中。在这之后,我们遍历哈希映射中的所有键值对,返回值最大的键。在遍历数组 nums 时候使用最大值比较的方法,维护最大的值,这样省去了最后对哈希表的遍历。
代码实现:
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int, int> counts;
int majority = 0, cnt = 0;
for (int num: nums) {
++counts[num];
if (counts[num] > cnt) {
majority = num;
cnt = counts[num];
}
}
return majority;
}
};
4.随机数法
class Solution {
public:
int majorityElement(vector<int>& nums) {
//随机选择一个数字,统计出现次数,目标出现频率大于50%,所以效率较高
while(true)
{
int random = rand() % nums.size();
int candidate = nums[random];
int count = 0;
for(int n:nums){
if(n == candidate)
++count;
}
if(count > nums.size()/2) return candidate;
}
return -1;
}
};
5.位运算
class Solution {
public:
int majorityElement(vector<int>& nums) {
int majority = 0;
for(int i = 0 ; i < 32; ++i){
int tmp = 0;
for(int n : nums){
//统计每个位置上1出现的次数
tmp += (n >> i) & 1;
}
majority += (tmp > nums.size()/2) << i;
//如果1出现次数大于数组的一半长度,1即为这个位置的目标数字
}
return res;
}
};