前言
看到封面和标题是不是想到了摩尔庄园?
刚开始我也以为跟摩尔庄园有关呢,然后才知道这是一个经典的算法
本题来自于牛客101题中的51题
题目的意思很简单,就是让我们找出数组中出现次数超过一半的数字。
但是要真正达到要求并不简单,这里的空间复杂度要求O(1)
问了AI才了解到原来有个摩尔投票算法
暴力求解
时间复杂度:O(n^2)
空间复杂度:O(1)
首先是喜闻乐见的暴力求解
没啥好说的,虽然也能过,但是时间复杂度太大了,不符合题目的要求
#include <vector>
using namespace std;
int majorityElement(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; i++) {
int count = 0;
for (int j = 0; j < n; j++) {
if (nums[j] == nums[i]) {
count++;
}
}
if (count > n / 2) {
return nums[i];
}
}
return -1; // 题目保证存在解,这里只是防止编译报错
}
哈希表法
时间复杂度:O(n)
空间复杂度:O(n)
先将数出现的次数都存放到哈希表里,然后再遍历一下表,找出关键数字
虽然优化了一些但还是不符合要求
#include <unordered_map>
#include <vector>
using namespace std;
int majorityElement(vector<int>& nums) {
unordered_map<int, int> count;
for (int num : nums) {
count[num]++;
if (count[num] > nums.size() / 2) {
return num;
}
}
return -1;=
}
我的方法
空间复杂度:O(1)
时间复杂度: O(n)
算是使用了计数排序的思想
但感觉还是略显笨拙,想找找更巧妙的算法
int MoreThanHalfNum_Solution(vector<int>& numbers) {
int num[10000]={0};
for(int i=0;i<numbers.size();i++)
{
num[numbers[i]]++;
}
for(int j=0;j<10000;j++)
{
if (num[j] >numbers.size()/2) return j;
}
return -1;
}
};
摩尔投票算法
空间复杂度:O(1)
时间复杂度: O(n)
终于到了今天的重头戏,让我们看看大佬到底是怎么想的
摩尔投票法是罗伯特·S·博耶和J·斯特罗瑟·摩尔在1981年发表发表的算法
其核心思想就是通过不同元素之间的抵消来找到可能的主要元素候选者
就像刚才的这个题,可以定义两个变量,一个用来记录当前出现的主要元素,另一个作为计数器,用来记录该元素出现的次数;
然后遍历数组,查看当前的数字,如果是主要元素,则计数器加一,反之则减一;
最后遍历完数组后因为主要元素出现的次数超过了数组的一半,所以就找到了那个出现次数超过数组总数一半的数字
int MoreThanHalfNum_Solution(vector<int>& numbers)
{
int candidate=0,votes=0;
for(int num:numbers)
{
if(votes==0) candidate=num;//当计数器为0时
//就替换主要元素为当前遍历到的元素
num==candidate?votes++:votes--;
}
return candidate;
}
果然大神的想法和普通人就是不一样