众数,顾名思义出现次数多的数,在leetcode定义的是指在长度为n 的数组中出现次数大于 n / 2的元素(假设总有一个)。
求众数,暴力方法就是遍历数组,用一个Map 统计各元素出现的次数。若只求其中一个众数,在遍历时可以顺便判断,当前元素出现的次数是否已经超过一半,若是直接返回就可以。这种算法,最坏的情况,时间复杂度为O(n), 空间复杂度也为O(n);
var majorityElement = function(nums) {
let objMap={};
let halfLength = nums.length/2;
for(let i=0;i<nums.length;i++){
const item=nums[i];
objMap[item]?objMap[item]++:objMap[item]=1;
if(objMap[item]>halfLength) return item;
}
};
还有一种摩尔投票法 Moore Voting,只需要O(n)的时间和O(1)的空间。 网上有很多关于这个算法的解释,个人觉得比较容易懂解释是:摩尔投票算法是基于这个事实:每次从序列里选择两个不相同的数字删除掉(或称为“抵消”),最后剩下一个数字或几个相同的数字,就是出现次数大于总数一半的那个。[来自于知乎]
就好比,我们有一排人手上都拿着不同色彩的气球,我们要知道哪种颜色的气球最多。上面的暴力方法就是统计各个颜色气球的数量。 摩尔算法就是拿一根针,从前往后,看到两个不同颜色的气球,就同时扎破他们,一直到最后,剩下的就是颜色最多的气球。
操作数组时,如果真去删除元素,时间开销很。可以先采用一个变量来标记第一个气球的颜色,再采用一个计数器来记录该颜色气球扫描到的未扎破的个数。依次扫描,每遇到一个颜色不一致的气球,扎破一个已经扫描过的当前颜色的气球,即计数器-1;每遇到一个相同颜色的的气球,个数加一,即计数器+1;直到扫描到下一个气球时,发现标记颜色的气球都破了,就是计数器为0;就重新标记当前气球的颜色,然后继续往下扫描,直到最后。最后标记颜色就是我们要找到最多的颜色。
var majorityElement = function(nums) {
let count=0;
let flagValue;
nums.forEach(item=>{
if(count===0){
flagValue=item
}
if(flagValue===item){
count++;
}else{
count--;
}
});
return flagValue;
};