摩尔投票法
描述:从第一个元素开始投票,默认候选人是第一个元素,从第二个开始投票,出现相同的数字,票数+1, 不同元素,票数-1,当票数减为0,更换候选人为当前元素;依次按照上述流程投票。直至整个数组扫描完毕,最终剩下的候选人即为众数。
本质:正负抵消问题。由于众数出现次数>n/2,持有的支持者的票数>反对者票数,即得到的票数一定是正数。
最终的候选者一定是众数!
public static int modeCount1(int[] nums)
{
int count=0;//票数统计
int cadidate=0;//候选人
for (int i:nums) {
if(count==0)
{
cadidate=i;
}
// if(i==cadidate)//进行投票
// {
// count++;
// }
// else {
// count--;
// }
//使用三目运算符代替分支语句
count += (i==cadidate) ? 1:-1;
}
//返回候选人
return cadidate;
}
时间复杂度:O(n),解决众数问题最优秀的解法
递归问题解决众数
典型的递归分治解决问题:将数组分为左右两个子区间,分别在子区间中寻找众数。
假设a是num数组的众数,将num划分为左右两个区间时,a至少是一个子区间的众数!
终止条件:当数组只剩下一个元素时,这个元素一定是当前数组的众数
//递归分治法解决众数问题:将数组分为左右两个子区间,分别在子区间中寻找众数
public static int modeCountRecursion(int[] nums)
{
return modeCountInternal(nums,0, nums.length-1);
}
/**
*返回nums[left...right]上的众数
* 众数出现的次数>n/2
* @param nums
* @param left
* @param right
* @return
*/
public static int modeCountInternal(int[] nums,int left,int right)
{
//1. base case
if(left==right)
{
//区间只剩下一个元素,自己就是众数
return nums[left];
}
int mid=left+((right-left)>>1);
//先得出左右两个子区间的众数
int leftMode=modeCountInternal(nums,left,mid);
int rightMode=modeCountInternal(nums,mid+1,right);
if (leftMode==rightMode)
{
//如果左右两个区间的众数相同,这个数字一定是区间上的众数
return leftMode;
}
//否则,这两个数在整个区间上出现的次数较多的是众数
int leftCount=countNum(nums,leftMode,left,right);
int rightCount=countNum(nums,rightMode,left,right);
//return leftCount>rightCount?leftCount:rightCount;
if(leftCount>rightCount)
return leftMode;
else
return rightMode;
}
public static int countNum(int[] nums,int target,int left,int right)
{
int count=0;
for (int i = left; i <=right; i++) {
if(nums[i]==target)
{
count++;
}
}
return count;
}