题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解决:
如果只是统计数组中的元素个数的话,显然没有利用这个数组的特点
比较简单的一个思路是:这个数字不管是最小最大还是居中,都会是这个数组的中位数
所以最开始的解决思路是,对数组进行快速排序,然后返回中间一位的值
但是快速排序本身的复杂度就是NlogN了,显然不是最优
最后采用的思路:
利用partition()函数获得某一中间数字,其余数字按大小排在该数字的左右。
若该数字下标刚好为n/2,则该数字即为所求数字;
若小于n/2,则在右边部分继续查找;反之,左边部分查找(递归)。
具体代码如下:
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array==null ||array.length<=0)
return 0;
int low=0;
int high=array.length-1;
int index=partition(array,low,high);//index也就是每次partition返回的中间数
while(index!=array.length>>1){//右移一位等于除以2,效率更高
if(index<array.length>>1){
low=index+1;
index=partition(array,low,high);//右递归
}else{
high=index-1;
index=partition(array,low,high);//左递归
}
}
//判断中位数出现的次数是否超过一半,如果没有超过一半则不存在要找的数字,则返回0
int num=array[index];
int times=0;
for(int i=0;i<array.length;i++){
if(array[i]==num){
times++;
}
}
if(times*2>array.length){
return num;
}
return 0;
}
//partition函数是快速排序的基础,low最终与high汇合,返回值为前半部分的最后一位
private int partition(int[] array,int low ,int high){
int Key=array[low];
while(low<high){ //这边low从low开始,而不是low+1
while(low<high && array[high]>=Key){
high--;
}
while(low<high && array[low]<=Key){
low++;
}
if(low<high){
int temp=array[low];
array[low]=array[high];
array[high]=temp;
}
}
return low;
}
}