LeetCode: 面试题 17.10. 主要元素
该题有以下三种解法:
方法一:HashMap
用hashmap对每一个元素出现的次数进行计数,当发现有一个元素出现的次数过半时返回该元素,若遍历完所有元素仍未发现次数过半的元素则返回-1。
class Solution {
public:
int majorityElement(vector<int>& nums) {
map<int, int> hashTable;
for(auto num : nums) {
hashTable[num]++;
if(hashTable[num] > nums.size() / 2) {
return num;
}
}
return -1;
}
};
方法二: 排序法
先对所有的元素进行排序(目的是把数值相同的元素放一起)然后当第i个元素和第i + nums.size() / 2个元素的值相同时,就找到了主要元素。
class Solution {
public:
int majorityElement(vector<int>& nums) {
if(nums.size() == 0) {
return -1;
}
sort(nums.begin(), nums.end());
for(int i = 0; (i + nums.size() / 2) < nums.size(); i++) {
if(nums[i] == nums[i + nums.size() / 2]) {
return nums[i];
}
}
return -1;
}
};
方法三:摩尔投票算法(重点来了,这也正是我写这篇博客的原因)
这是后来看题解发现的方法,也是第一次听说这个算法。
用一个例子来解释这个算法,假设你面前有n(n很大)张选票,每张选票上有一个候选人ID,你需要找到票数过半的候选人。
Step1:用右手拿一张选票;
Step2:若左手中无选票,将右手中的选票放到左手上;若左手中有选票,如果两张选票上候选人ID相同,则将右手中选票放到左手上,反之将右手中的选票和左手中的一张选票丢到一边;
Step3: 重复Step1和Step2,直到遍历完所有选票;
Step4:若最后左手上无选票,则不存在票数过半的候选人,反之,左手上的选票就有可能是候选人;
Step5:验证左手上的候选人选票是否过半。
因为你每次丢掉的选票都是投不同的人的,所以如果最后左手中没有一张选票则说明票数最多的候选人最多有一半票数,即每次丢掉的两张选票中都有一张投他的。
如果最后左手里还有选票,那这些选票上投的人就有可能是票数过半的人我们在检查一下选票验证就行了。
以下代码中currElement就是左手中选票的候选人ID,counter是对左手中选票的计数。
class Solution {
public:
int majorityElement(vector<int>& nums) {
int counter = 0;
int currElement = 0;
for(auto num : nums) {
if(counter == 0) {
currElement = num;
counter++;
}
else if(num == currElement) {
counter++;
}
else {
counter--;
}
}
if(counter != 0) {
counter = 0;
for(auto num : nums) {
if(num == currElement) {
counter++;
if(counter > nums.size() / 2) {
return currElement;
}
}
}
}
return -1;
}
};