【前言】最近再刷leetcode的时候,遇到了一道关于主要元素的题目,题目如下:
【问题2】
Given an array of size , find the majority element. The majority element is the element that appears more than⌊ n/2 ⌋ times.You may assume that the array is non-empty and the majority element always exist in the array.
然后发现了一个类似投票的算法:A Linear Time Majority Vote Algorithm点击打开链接
算法主要解决在元素序列中找到出现次数较多的元素。
算法思想:
每次都找出一对不同的元素,从数组中删掉,直到数组为空或只有一种元素。
不难证明,如果存在元素e出现频率超过半数,那么数组中最后剩下的就只有e。
【解决思路】定义一个记录次数的数组count,count如果为0,则把改变当前候选者元素candidate,并把count设为1;否则根据当前元素e与候选者元素candidate比较来决定增加或减去count,最后的候选者元素即为所求;
候选者元素candidate即出现的count(次数)最多的元素。
When we move the pointer forward over an element e:
- If the counter is 0, we set the current candidate to e and we set the counter to 1.
- If the counter is not 0, we increment or decrement the counter according to whethere is the current candidate.
该题目中需要定义一个count,对应candidate出现的次数,代码如下:
public int majorityElement3(int[] nums) {
if(nums.length==0)
return 0;
int count=0;
int candidate=0;
for(int i : nums){
if(candidate ==i)
count++;
else if(count==0){
candidate =i;
count=1;
}
else
count--;
}
count=0;
for(int i : nums){
if(i==candidate)
count++;
}
return count>nums.length/2?candidate :0;
}
【问题2】
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.
该题目中需要定义一个count数组,分别对应两个candidate出现的次数(元素出现次数大于n/3,至多两个candidate),代码如下:
/**
* 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.
* @param nums
* @return
*/
public List<Integer> majorityElement2(int[] nums) {
/*
A Linear Time Majority Vote Algorithm
每次都找出一对不同的元素,从数组中删掉,直到数组为空或只有一种元素。
不难证明,如果存在元素e出现频率超过半数,那么数组中最后剩下的就只有e。
top 2 Majority Element (more than n/3 times.)
*/
List<Integer> list=new ArrayList<Integer>();
if(nums==null)
return list;
int[] count=new int[2];
int[] candidate=new int[2];
candidate[0]=0;
candidate[1]=1;
for(int i : nums){
if(candidate[0]==i){
count[0]++;
}
else if(candidate[1]==i){
count[1]++;
}
else if(count[0]==0){
candidate[0]=i;
count[0]=1;
}
else if(count[1]==0){
candidate[1]=i;
count[1]=1;
}
else{
count[0]--;
count[1]--;
}
}
for(int j=0;j<2;j++){
count[j]=0;
}
for(int k : nums){//验证count是否满足n/3
if(k==candidate[0])
count[0]++;
else if(k==candidate[1])
count[1]++;
}
for(int l=0;l<2;l++){
if(count[l]>nums.length/3&&!list.contains(candidate[l]))
list.add(candidate[l]);
}
return list;
}
总结:上述算法的时间复杂度为O(n),而由于并不需要真的删除数组元素,我们也并不需要额外的空间来保存原始数组,空间复杂度为O(1)。