579,摩尔投票算法解主要元素
This world may be rough around the edges, but it’s got its charms.
这个世界可能很粗野,但有其魅力所在。
问题描述
来源:LeetCode面试题 17.10
难度:简单
数组中占比超过一半的元素称之为主要元素。给你一个整数数组,找出其中的主要元素。若没有,返回-1。请设计时间复杂度为O(N)、空间复杂度为O(1)的解决方案。
示例 1:
输入:[1,2,5,9,5,9,5,5,5]
输出:5
示例 2:
输入:[3,2]
输出:-1
示例 3:
输入:[2,2,1,1,1,2,2]
输出:2
摩尔投票算法解决
这题是让求主要元素,主要元素就是在数组中占比超过一半的元素。咋一看这题很简单,我们可以通过排序或者使用HashMap都是可以解决的。但这题要求时间复杂度为O(N),空间复杂度为O(1),很明显上面两种方式都不符合要求。
除了上面两种方式我们可以使用摩尔投票算法来解,维基百科对摩尔投票算法是这样解释的。
摩尔投票算法是在集合中寻找可能存在的多数元素,这一元素在输入的序列重复出现并占到了序列元素的一半以上;在第一遍遍历之后应该再进行一个遍历以统计第一次算法遍历的结果出现次数,确定其是否为众数;如果一个序列中没有占到多数的元素,那么第一次的结果就可能是无效的随机元素。对于数据流而言,则不太可能在亚线性空间复杂度的情况下中就寻找到出现频率最高的元素;而对于序列,其元素的重复次数也有可能很低。
上面说了一大堆,主要说了两层意思:
第一就是找出主要元素(不一定有)
第二判断这个数是否是主要元素。
摩尔投票算法的原理就是使用两个变量,一个major记录当前数字,一个count记录当前数字出现的次数,遇到相同的count就加1,遇到不同的就减1,当count小于0的时候,说明前面的都相互抵消完了,major和count都要重新赋值……,最后再判断major是否是主要元素即可。我们来举个例子
假设数组中每个不同的数字就代表一个国家,而数字的个数就代表这个国家的人数,他们在一起混战,就是不同国家每两个人都同归于尽。我们就可以知道那个人数大于数组长度一半的肯定会获胜(假设主要元素存在)。
就算退一万步来说,其他的所有人都来攻击这个人数最多的国家,他们每两个两个同归于尽,最终剩下的也是那个主要元素,(这里有个前提,就是主要元素必须存在),来看下代码
1public int majorityElement(int[] nums) {
2 //边界条件判断,如果数组为空就返回-1
3 if (nums == null || nums.length == 0)
4 return -1;
5 //先找出主要元素
6 int major = nums[0];
7 int count = 1;
8 for (int i = 1; i < nums.length; i++) {
9 if (major == nums[i]) {
10 //如果当前元素等于major,count就加1
11 count++;
12 } else {
13 //否则count就减1,
14 count--;
15 if (count < 0) {
16 //如果count小于0,说明前面的
17 //全部抵消了,这里在重新赋值
18 major = nums[i];
19 count = 1;
20 }
21 }
22 }
23 //下面是判断主要元素是否存在
24 count = 0;
25 int half = nums.length >> 1;
26 for (int num : nums) {
27 if (major == num)
28 if (++count > half)
29 return major;
30 }
31 return -1;
32}
时间复杂度:O(N),两个for循环,不是嵌套的。
空间复杂度:O(1),使用了两个变量。
截止到目前我已经写了500多道算法题了,为了方便大家阅读,我把部分算法题整理成了pdf文档,目前有1000多页,大家可以在公众号中回复关键字“pdf”即可获取下载链接。