这道题目是Moore Voting Algorithm的变体,找到数组中出现次数大于n / 3(int算法)的元素,注意到这里说的是严格的大于,所以这样的数字最多有两个。第一次遍历的时候使用Moore Sorting Algorithm找出两个可能为众数(概念不严格,借用一下)的数字,然后再进行第二次遍历进行检查它们出现的次数是不是大于n / 3,注意到题目中并没有说明一定会出现两个众数,所以在第一遍遍历之后可能出现三个情况:
1. number1和number2出现的次数均小于n / 3,那么在第二遍遍历的时候就会被排除掉;
2. number1和number2中只有一个数字出现的次数大于n / 3,那么最终只有一个留下;
3. number1和number2出现次数都大于n / 3,这就是最终的结果
时间复杂度为O(n),空间复杂度为constant,代码如下:
public class Solution {
public List<Integer> majorityElement(int[] nums) {
List<Integer> result = new ArrayList<Integer>();
if(nums == null || nums.length == 0) return result;
int number1 = nums[0];
int number2 = nums[0];
int count1 = 0;
int count2 = 0;
int length = nums.length;
// Find two majority numbers
for(int i = 0; i < nums.length; i++){
if(nums[i] == number1){
count1++;
}else if(nums[i] == number2){
count2++;
}else if(count1 == 0){
number1 = nums[i];
count1++;
}else if(count2 == 0){
number2 = nums[i];
count2++;
}else{
count1--;
count2--;
}
}
// Find the frequency of two nunbers found above
count1 = 0;
count2 = 0;
for(int i = 0; i < nums.length; i++){
if(nums[i] == number1){
count1++;
}else if(nums[i] == number2){
count2++;
}
}
if(count1 > length / 3) result.add(number1);
if(count2 > length / 3) result.add(number2);
return result;
}
}
这道题目的算法的思路确实比较巧妙,想了很久也难以用很通俗的语言去解释,只是自己试了很多例子之后发现都非常适用,可以记住这个在一系列数字之中寻找众数的方法,Moore Voting Algorithm一开始是为了找出数组中的众数,即出现次数大于n / 2的元素,但是可以对其进行多个变化,进而能够寻找数组中出现次数大于n / k的元素(算法的变形方式和这道题目相似)。
知识点:
1. 记住Moore Sorting Algorithm的基本算法,适用情况及其寻找数组中出现次数大于n / k的元素的变体