刷剑指offer的过程中遇到一道题,借鉴了一位大佬的博客会找到3种解法,于是把这二种写法记录在这里。
题目
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解法一
由于要求出出现次数超过长度一半的的数字。我们可以先对其排序,然后可以发现处在数组中位数的数字可能就是我们要找的出现次数超过半数的数字。比如{1,2,2,2,2,2,3,4,5}
然而还有一种情况是该数字出现次数小于等于数组长度的一半,这样该数字同样也会出现在中位数上,但是这种情况是不对的。比如{1,2,2,2,2,3,4,5}
{1,2,2,2,3,4,5}。
结论:出现次数最高的数字肯定会出现在中位数上。
所以我们只要把出现次数最高的数字再进行判断次数是否真正超过数组长度一半即可以得出正确结果。
public int MoreThanHalfNum_Solution(int [] array) {
quickSort(array,0,array.length-1);
//求出中位数
int mid = (array.length-1)/2;
int count=0;
for(int i =0 ;i<=array.length-1;i++){
if (array[i]==array[mid]){
count++;
}
}
if (count>array.length/2){
return array[mid];
}
return 0;
}
//使用快速排序
public void quickSort(int [] array,int low,int high){
if(low <high){
int pos = position(array,low,high);
quickSort(array,low,pos-1);
quickSort(array,pos+1,high);
}
}
//快速排序中返回位置
public int position(int[] array, int low ,int high){
int pivot = array[low];
if(low<high){
while(array[high]>pivot&&low<high)high--;
array[low]=array[high];
while(array[low]<pivot&&low<high)low++;
array[high]=array[low];
}
array[low] = pivot;
return low;
}
解法二
数组中的数字如果超过数组长度的一半,那么就是说明了这个数字的数量比其他数字的数量之和还要多。我们可以使用now,times值。now初始值为数组的第一个数。当遍历这个数组的时候,一个数字出现一次,则记录times++;如果出现了其他数字,times --。当times减到0,则需要更换now的值,并且继续开始times++。
到遍历到最后的时候,结果会有两种情况:(1)now是出现次数最多且超过数组长度一半的数字。(2)now是数组的最后一个数字。
于是还需要重新遍历,查找该数字是否为真正出现次数超过数组长度一半的数字。
public int MoreThanHalfNum_Solution(int [] array) {
int times=0;
int now=array[0];
for(int i=0;i<array.length;i++){
//如果相等则加一
if(array[i]==now){
times++;
}
//如果不相等则减少
if(array[i]!=now){
times--;
//如果出现次数减少到0,则更换now数字,并且开始计数
if(times==0){
now = array[i];
times++;
}
}
}
times=0;
//重新需要判断最后得到的数是否超过长度一半
for(int i=0;i<array.length;i++){
if(array[i]==now)
times++;
if(times>array.length/2)
return now;
}
return 0;
}