LeetCode OJ 229. Majority Element II

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorithm should run in linear time and in O(1) space.

Hint:

  1. How many majority elements could it possibly have?
  2. Do you have a better hint? Suggest it!

【题目分析】

在Majority Element中我们使用了一个巧妙的算法就是Moore's alogoirthm,在上一个题目中我们寻找的是the elements that appear more than ⌊ n/2 ⌋ times。

假设⌊ n/2 ⌋ = k,那么n最大值为2k+1,Majority Element至少为k+1个,因此Majority Element最多只能有一个。我们设置两个变量 ME 和count,ME用来存储当前的Majority Element,count对当前ME进行计数,计数规则如下。遍历数组,如果count = 0,则把当前元素赋给ME;否则的话如果当前元素=ME,则count++,否则count--;这个过程结束和,最后的EM肯定是我们Majority Element。

那么对于当前题目,设⌊ n/3 ⌋ = k,那么n最大为3k+2。如果有这样的元素它出现的个数大于k,那么这样的元素最多有两个(3k+2-2k-2 = k)。我们是否还可以用Moore's alogoirthm来解决我们的问题呢?

因为最多只能有两个Majority Element,我们设置如下几个变量:EM1,EM2,count1,count2,用来表示两个Majority Element和他们的计数。我们讨论一下下面几种情况:

1. 不存在Majority Element。那么我们最后会得到一个结果,但是这个结果可能是不正确的,需要重新遍历一次数组来对找到的元素进行计数;

2. 存在两个Majority Element。我们知道 count(EM1) >= k+1, count(EM2) >= k+1,剩余的数字 count(remain) <= k。遍历数组的过程中,如果当前元素和EM1,EM2都不相同,那么count1--,count2--,最后的结果肯定是Majority Element,因为他们的数目比其他元素多,count数不会被减到0;

3. 存在一个Majority Element。此时count(EM1) >= k+1,那么在算法执行的过程中EM1是否会被减到0呢?比如k+1个EM1出现在数组的最前面,在遍历到其他数字时,由于count(remian)<= 2k+2,因此我们担心这样的过程会导致不能找到正确的Majority Element,但事实是我们会得到正确的结果。假设最坏的情况:剩下的k+2个数字是互不相同的,如下:

[1,1,1,1,2,3,4,5]

这个数组中有8个元素,Majority Element是1,剩下的元素互不相同。在遍历前四个元素的时候count1加到4,当到达第五个元素时候,该元素不等于EM1,此时count2 = 0,因此我们会把当前元素赋值给EM2,此时count1并不发生变化。遍历到第六个元素时,当前元素与EM1和EM2都不相同。此时count1和count2才会减1。继续这个过程直到遍历完成所有的元素,我们可以看到在这个过程中,剩下的元素有一半会被赋值给EM2,而另一半元素才会使得count1--。因此count1最多减(2k+1)/2 = k次,所以如果只有一个Majority Element的话,它肯定会出现在结果中。上面只是举了最坏的情况,对于任意一种排列方式,和任意的情况这个结论都是成立的。


【java代码】

 1 public class Solution {
 2     public List<Integer> majorityElement(int[] nums) {
 3         List<Integer> list = new ArrayList<Integer>();
 4         if(nums == null || nums.length == 0) return list;
 5         
 6         int num1 = nums[0], num2 = 0;
 7         int count1 = 0, count2 = 0;
 8         
 9         for(int i = 0; i < nums.length; i++){
10             if(num1 == nums[i]) count1++;
11             else if(num2 == nums[i]) count2++;
12             else if(count1 == 0){
13                 num1 = nums[i];
14                 count1++;
15             }
16             else if(count2 == 0){
17                 num2 = nums[i];
18                 count2++;
19             }
20             else{
21                 count1--;
22                 count2--;
23             }
24         }
25         
26         count1 = 0; count2 = 0;
27         for(int i = 0; i < nums.length; i++){
28             if(nums[i] == num1) count1++;
29             else if(nums[i] == num2) count2++;
30         }
31         if(count1 > nums.length/3) list.add(num1);
32         if(count2 > nums.length/3) list.add(num2);
33         
34         return list;
35     }
36 }
原文地址:https://www.cnblogs.com/liujinhong/p/5628599.html