闻道有先后,术业有专攻,如是而已。——韩愈《师说》

1 问题定义

首先,摩尔投票算法不是解决一组数求众数问题,它的约束还要多一个。即找到 n 个数中出现次数超过 n/2 的数。也就是说给定 n 个数只有两个结果,要么不存在次数超过 n/2 的数,要么存在次数超过 n/2 的数,如果不存在就返回不存在,如果存在就返回是哪个数次数超过 n/2 。
力扣参考: 面试题 17.10. 主要元素 和 169. 多数元素

2 理解算法

首先,该问题可以用任何求众数的算法解决,但是时间空间效率较佳的是摩尔投票法,O(1)的空间复杂度,O(n)的时间复杂度。摩尔投票法充分利用了超过 n/2 这个条件。我喜欢用同归于尽去理解的它。举个例子,假设六大门派围攻光明顶,明教教徒众多,一个明教教徒和任意一个门派的教徒同归于尽,如果明教教徒足够多,那么取胜的就是明教,反之,明教就被灭了。

3 具体算法逻辑

遍历数组,维护两个变量count和num_now,分别统计当前出现次数最多的元素次数和数值。初始化count=0,num_now=nums[0]。这些数nums[i](教徒)依次登上擂台。
遍历到任意一个数(教徒)有3种结果:
1.count=0。即擂台现在是空的,那么登上擂台,count=1,num_now=nums[i];
2.count!=0 && num_now==nums[i]。即擂台上有人,都是我这个门派的,那我加入他们,count++;
3.count!=0 && num_now!=nums[i]。即擂台上有人,但是是其他门派的,让他们派出一个人和我同归于尽,count- -;

4 java实现

4.1 力扣【169.多数元素】

class Solution {public int majorityElement(int[] nums) {//维护两个变量int count=0;//出现次数int num_now=0;//当前的数字for(int i=0;i<nums.length;i++){//当前无人,站上擂台if(count==0){num_now = nums[i];count++;}//有和我一样的人,站队else if(nums[i]==num_now) count++;//擂台上的和我不一样,同归于尽else count--;}//返回return num_now;}
}

4.2力扣【面试题 17.10. 主要元素】
注意该题和上述题还有些不一样,它不保证给的数组一定有出现次数超过 n/2 的数,所以还要加判断。

class Solution {public int majorityElement(int[] nums) {//维护两个变量int count=0;//出现次数int num_now=0;//当前的数字for(int i=0;i<nums.length;i++){//当前无人,站上擂台if(count==0){num_now = nums[i];count++;}//有和我一样的人,站队else if(nums[i]==num_now) count++;//擂台上的和我不一样,同归于尽else count--;}//统计确认是不是大于n/2count=0;for(int i=0;i<nums.length;i++){if(nums[i]==num_now) count++;}if(count>nums.length/2) return num_now;else return -1;}
}

5 进阶

力扣:229. 求众数 II 给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。
此时光明顶就可能不是只有一个赢家了,最多有两个门派成为赢家。所以需要维护两套count和now_num。遍历来了一个新的数有五种可能:
1.站上擂台,成立门派1;
2.站上擂台,成立门派2;
3.加入门派1;
4.加入门派2;
5.三个人一起同归于尽。
有很多博主和力扣的解答在判断语句里面写的很简洁,确实可以优化,但是读起来要多思考一下。这里面要注意的点就是,成立门派的时候首先要判断你属不属于另一边的门派,不能立两个中央啊。另外就是在统计最后出现次数的个数的时候,要考虑 num_now1 和 num_now2 是同一个数的情况(输入就一个数)。

class Solution {public List<Integer> majorityElement(int[] nums) {//保存输出的listArrayList<Integer> out = new ArrayList<Integer>();//为空检测if(nums.length==0) return out;//维护四个变量int count1 = 0;//出现次数int num_now1 = nums[0];//当前的数字int count2 = 0;//出现次数int num_now2 = nums[0];//当前的数字for (int i = 0; i < nums.length; i++) {//新成立门派1if (count1 == 0 && num_now2 != nums[i]) {num_now1 = nums[i];count1++;continue;}//新成立门派2if (count2 == 0 && num_now1 != nums[i]) {num_now2 = nums[i];count2++;continue;}//加入门派1if (num_now1 == nums[i]) {count1++;continue;}//加入门派2if (num_now2 == nums[i]) {count2++;continue;}//不是上面所有情况,同归于尽count1--;count2--;}//统计最多的两个数的个数count1 = 0;count2 = 0;for (int i = 0; i < nums.length; i++) {if (nums[i] == num_now1)count1++;else if(nums[i] == num_now2)count2++;}//如果超过1/3就返回if (count1 > nums.length / 3)out.add(num_now1);if (count2 > nums.length / 3)out.add(num_now2);return out;}
}

如果是出现次数大于 n/4 呢?n/5呢?又如何解决。

6 总结

该题没有涉及复杂的数据结构,但是几个if-else的应用非常精妙,值得好好品味,continue的使用也可以很好的减少代码量。刷十题不如好好总结一题,扩展衍生举一反三。

理解并实现摩尔投票算法相关推荐

  1. java 投票算法_摩尔投票算法 - woshixin的个人空间 - OSCHINA - 中文开源技术交流社区...

    摩尔投票算法(Moore majority vote algorithm) 这个在wiki的介绍在https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_m ...

  2. 算法 摩尔投票算法(图解例题)

    摩尔投票算法 摩尔投票算法也叫多数投票算法 摩尔投票法,解决的问题是如何在任意多的候选人中,选出票数超过一半的那个人.注意,是超出一半票数的那个人. 假设投票是这样的,[A, C, A, A, B], ...

  3. Boyer–Moore majority vote algorithm(摩尔投票算法)

    Boyer–Moore majority vote algorithm 摩尔投票算法 Leetcode15: https://leetcode.com/problems/majority-elemen ...

  4. 2020年 Moore majority vote algorithm 摩尔投票法知多少

    第一眼看到这个题目,想到的是使用Map来统计出现频次,然后遍历找出频次大于n/2的元素. class Solution {public int majorityElement(int[] nums) ...

  5. Boyer-Moore 投票算法

    文章目录 算法概述 题目 k=2 思路 代码 复杂度分析 k=3 思路 代码 复杂度分析 算法概述 摩尔投票算法经常用于求众数的题目,即,求 出现次数>n/k 的数,可以证明,出现次数超过 n/ ...

  6. Boyer-Moore 投票算法小析

    今日get到摩尔投票算法,时间和空间复杂度都得到了最优的结果,觉得非常经典,在此记录,以备今后查阅,同时希望对和我一样的初学者起到抛砖引玉的效果. CiterSeerX上论文链接: https://c ...

  7. 摩尔投票法(Boyer–Moore majority vote algorithm)

    参考资料 论文MJRTY A Fast Majority Vote Algorithm 算法演示网站 维基百科 算法解读 概述 摩尔投票法(Boyer–Moore majority vote algo ...

  8. C语言刷题之摩尔投票法

    目录 1.引入 2.摩尔投票算法 3.基本步骤 摩尔投票法分为两个阶段: 1.抵消阶段 2.检验阶段 4.代码实现 5.扩展沿伸 6.总结 1.引入 我们来看一个问题: 假设有一个无序数组长度为n,要 ...

  9. 小小算法,可笑可笑——摩尔投票法(集万家之长)

    摩尔投票法 不多说,先上题目. 问题描述:leetcode 229题 给定一个大小为 n 的整数数组,找出其中的所有的出现超过 ⌊ n/3 ⌋ 次的元素. 这还不简单!直接暴力计数,上map,easy ...

最新文章

  1. Linux test 命令
  2. jmeter接口测试----9函数助手: random, counter, time
  3. html转换pdf软件,html转换成高质量的PDF文件[跨平台开源软件]
  4. svn代码版本管理总结
  5. C#基础概念二十五问[转]
  6. 2019年“深圳杯”数学建模挑战赛B题解题思路(一)
  7. 《区块链开源技术需求调研报告》拍了拍你
  8. struts1,struts2,springMVC终极对比
  9. 重装后显示计算机无法联网,Win10重装系统后无法联网如何解决
  10. Java:计算圆的面积和周长
  11. 动态像素绘画——StarDust
  12. 【华为OD机试真题 C++】1023 - 按身高和体重排队 | 机试题+算法思路+考点+代码解析
  13. 今天睡眠质量记录77
  14. 安卓手机如何一键去水印
  15. WPS怎么转换成PDF?这样转换准没错
  16. 开发板——在X210开发板上进行裸机开发的流程
  17. JVM参数 之 -XX:MaxGCPauseMillis 与 -XX:GCTimeRatio
  18. 新手坐高铁怎么找车厢_新手坐高铁怎么找车厢 - TABUZHE
  19. php 字符串 大小,字符串如何比较大小?
  20. Oracle加入NoSQL阵营

热门文章

  1. 带你学习c++系列(二)造了几本书
  2. 2021年制冷与空调设备运行操作考试试卷及制冷与空调设备运行操作试题及解析
  3. 传感器技术实验及实训QY-812G
  4. java使用百度人脸识别API
  5. 如何选择适合你的兴趣爱好(三十一),围棋
  6. 2022-2028全球与中国迷你可变光衰减器(迷你VOA )市场现状及未来发展趋势
  7. 微信3.1.0.72逆向-微信3.1.0.72HOOK接口说明(WeChatHelper.dll)-获取个人信息
  8. 基于角蜂鸟的智能监控
  9. 龙应台祝贺莫言获诺奖:好家伙你得奖了-莫言-诺贝尔文学奖-龙应台
  10. Android项目Tinder学习一