问题描述
给定一个无序数组,有n个元素,找出其中的一个多数元素,多数元素出现的次数大于一半,注意数组中也可能不存在多数元素,如果存在多数元素则返回该多数元素,否则返回-1。
常规解法
解法1
先排序,判断是否存在主要元素。由于需要排序,那么时间复杂度为O(nlogn);空间复杂度为O(1)。
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
for(int i = 0; (i+nums.size()/2) < nums.size(); i++)
{
//每次步进一半的元素就可以判断num[i]是否为主要元素
if(nums[i] == nums[i+nums.size()/2])
return nums[i];
}
return -1;
}
解法2
哈希表计数,如果计数值>size/2返回。时间复杂度为O(n)。由于要用到哈希表因此空间复杂度为O(n)。
int majorityElement(vector<int>& nums) {
unordered_map<int, int> hash;
for(auto x : nums)
{
hash[x]++;
if(hash[x] > nums.size()/2)
return x;
}
return -1;
}
多数投票算法
原理解析:核心就是对拼消耗。如果存在多数元素,用count记录在count为0前的多数元素值。先假设一个多数元素,如果遇到多数元素,count值加一;如果遇到非多数元素,count值减一。如果假设的多数元素就是真实的多数元素,那么当count减为0时,我们消耗掉了与多数元素一样多的非多数元素,数组剩余部分中的多数元素数值不变。如果假设的多数元素不是真正的多数元素,那么我们还消耗了非多数元素,数组剩余部分中的多数元素数值变多。这两种情况证明了关键的一点数组中从起始点到count减到0的那一段可以被去除,余下部分的多数元素依然是原数组的多数元素。我们可以不断重复这个过程,直到扫描到数组尾部,那么count必然会大于0,而且这个count对应的候选元素就是原数组的多数元素。最后再看不存在多数元素的情况,我们只需要在最后对原数组进行遍历,验证找到的多数元素是否满足需求即可。
具体代码如下:
int majorityElement(vector<int>& nums) {
int x = 0, votes = 0, count = 0;
for(int num : nums){
if(votes == 0)
x = num;
votes += num == x ? 1 : -1;
}
// 验证 x 是否为多数元素
for(int num : nums)
if(num == x) count++;
return count > nums.size() / 2 ? x : -1; // 当无多数元素时返回 -1
}
多数投票算法时间复杂度为O(n),空间复杂度为O(1)。