题目描述:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如{2,1,3,2,2,2,2,5,4,2,2,2,2},由于数字2的个数超过了数组长度的一半,则输出2.
解题思路1:
数组排序后有一个特征:数组中如果有超过一半长度的数字,则排序之后位于数组中间的数字一定是超过一半的数字。也就是中位数。受快速排序的启发,随即找出一个数字,如果其最终位置位于n/2,则这个数字就是中位数。如果最终位置大于n/2,则中位数一定位于其左边,递归查找其左边。如果最终位置小于n/2,则位于数组右边,递归查找右边。
解题思路2:
数组中如果有超过一半长度的数字,则它出现的次数比其他所有数字的出现的总次数都要多。因此,遍历时保存两个值,一个是数组中的数字,一个是出现次数。当遍历到下一个数字时,如果下一个数字和当前数字相同则times++,如果和下一个数字不同,则times--;如果次数为0,则重新保存下一个数字并将times置为1.如果存在次数超过一半,最后一次置为1的数字,一定是出现次数超过一半的数字。
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String a=in.nextLine();
String b[]=a.split(" ");
int temp[]=new int[b.length];
for(int i=0;i<b.length;i++){
temp[i]=Integer.valueOf(b[i]);
}
System.out.println(MoreThanHalf(temp,b.length));
System.out.println(MoreThanHalf2(temp,b.length));
}
static int MoreThanHalf(int a[],int length){
int middle=length/2;
int star=0;
int end=length-1;
int index=partition(a,star,end);
while(index!=middle){
if(index>middle){
end=index-1;
index=partition(a,star,end);
}
else{
star=index+1;
index=partition(a,star,end);
}
}
int times=0;
int result=a[middle];
for(int i=0;i<length;i++){//判断是否超过一半
if(a[i]==result)
times++;
}
if(times*2<=length)
return -1;
return result;
}
public static int partition(int[] a, int low, int high){
int key = a[low];//基准元素,排序中会空出来一个位置
while(low<high){
while(low<high && a[high]>=key){//从high开始找比基准小的,与low换位置
high--;
}
a[low]=a[high];
while(low<high && a[low]<=key){//从low开始找比基准大,放到之前high空出来的位置上
low++;
}
a[high]=a[low];
}
a[low]=key;//此时low=high 是基准元素的位置,也是空出来的那个位置
return low;
}
}
解题思路2代码:
static int MoreThanHalf2(int a[],int length){
int result=a[0];
int times=1;
for(int i=1;i<length;i++){
if(times==0){
result=a[i];
times=1;
}
else if(a[i]==result)
times++;
else times--;
}
int t=0;
for(int i=0;i<length;i++){//判断是否超过一半
if(a[i]==result)
t++;
}
if(t*2<=length)
return -1;
return result;
}