LeetCode169-多数元素 - 摩尔投票法

题目描述

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

 

我的题解

第一想法是把每个元素出现的次数统计下,找出次数大于n/2的即可,使用hashmap实现:

 1     public int majorityElement(int[] nums) {
 2  3         Map<Integer,Integer> map =new  HashMap<>();
 4         for(int n: nums){
 5             if (map.containsKey(n)){
 6                 map.put(n,map.get(n)+1); //数量+1
 7             }
 8             else{
 9                 map.put(n,1); //第一次出现,初始化为1
10             }
11         }
12         int size = nums.length/2;
13         for (Map.Entry<Integer,Integer> e: map.entrySet()){
14             if (e.getValue()>size){
15                 return e.getKey();                
16             }
17         }
18         return -1;
19 }

时间复杂度是O(nlogn),空间复杂度是O(n)

性能实际上并不是很好。

其他解法

分析题意,可知‘多数元素’(众数)一定存在,且一定只有一个(两个总长度超出了n),数量大于n/2。

于是:对数组进行排序后,中间这个数一定是众数。

1  Arrays.sort(nums);
2  return nums[nums.length / 2];

代码简洁,时间/空间复杂度取决于使用的排序算法,时间复杂度不可能达到O(N).

还有更好的解法:

最优解 · 摩尔投票法

算法思想

核心思想是 对拼抵消,比如老师和学生干架,一个学生和一个老师能"同归于尽",由于学生数量比老师多,所以最后学生一定是赢家。

这里也是一样的,这个每次两个不同的数抵消,最后剩下的一定是众数。

 1 public int majorityElement(int[] nums) { 
 2         int res= nums[0];//取一个数,不知道是众数还是其他数。
 3         int count = 0;   //统计这个数出现的次数。
 4         for(int num : nums) {//遍历数组
 5             if(num != res) { //如果取到的数和res不同,说明要让它们'同归于尽',即count-1,并移到下一个数。
 6                 count--;
 7                 if(count == 0) { //如果count为0,表示当前统计的这个数数目为0,不能在被抵消,这时必须换一个数,以能够被抵消
 8                     count = 1;
 9                     res = num; //num虽然被抵消了,但是赋给res并不影响,因为后面可以还有和num相同的值,如果不同就会一直过渡下去。
10                 }
11             }
12             else
13                 count++; //相同就数量+1,
14         }
15         return res;
16 
17 }    

时间复杂度O(N),空间复杂度O(1)

 

posted @ 2020-03-14 13:16  Edwin_Xu  阅读(122)  评论(0编辑  收藏  举报