找到数量超过一半的数字
如果没有返回0.
统计一个数字出现的次数,最简单的想到的就是排序,排序算法的复杂度为O(logn)。
所以这个题肯定是根据数组本身特点来做,一个数超过一半,则说明排好序之后这个数一定在数组中间。
出现的次数比其他数字出现的次数加起来还要多。
所以设置两个变量,一个保存数字,一个保存次数。遍历时,**如果它与之前的数字相同则次数加1,不相同则次数减1.若次数为0,则保存下一个数字并将次数变为1.**这样的话遍历完之后这个数字一定是出现最多的。
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array==null || array.length==0){
return 0;
}
int time=1;
int num=array[0];
for(int i=1;i<array.length;i++){
if(time==0){
time++;
num=array[i];
}else{
if(array[i]==num){
time++;
}else{
time--;
}
}
}
time=0;
for(int i=0;i<array.length;i++){
if(array[i]==num){
time++;
}
}
return time>array.length>>1?num:0;
}
}
第二种做法就是基于partition做法,这个题其实就是把排序好的数组分成两半的话,中位数肯定是这个数(如果存在超过一半的数)
首先对一个数组的全部进行partition,得到其中一个随机数左边比他小右边比它大的数组的下标数组,如果这个下标下限大于mid,说明这个超过一半的数在左边,如果下标小于mid,说明在右边,循环partition,直到这个数的下标在中间,则这个数就可能是那个数了,再检查这个数的个数是否超过一半,如果超过则返回这个数,没有超过则返回0
partition就是首先选一个随机数,然后遍历数组,把比它小的数放到左边,把比它大的放到右边和它一样大的放中间。partition完之后,返回等于它的最小最大的坐标。这样的复杂度是O(n)。
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array==null || array.length==0){
return 0;
}
int mid=array.length>>1;
int lo=0;
int hi=array.length-1;
int[] s=partition(array,lo,hi);
while(s[0]>mid || s[1]<mid){
if(s[0]>mid){
hi=s[0]-1;
s=partition(array,lo,hi);
}else{
lo=s[1]+1;
s=partition(array,lo,hi);
}
}
int time=0;
for(int i=0;i<array.length;i++){
if(array[i]==array[s[0]]){
time++;
}
}
return time>mid?array[s[0]]:0;
}
public int[] partition(int [] arr,int lo,int hi){
int ran=lo+(int)(Math.random()*(hi-lo+1));
swap(arr,ran,hi);
int cur=lo;
int less=lo-1;
int more=hi;
while(cur<more){
if(arr[cur]<arr[hi]){
swap(arr,++less,cur++);
}else if(arr[cur]>arr[hi]){
swap(arr,--more,cur);
}else{
cur++;
}
}
swap(arr,more++,hi);
return new int[]{less+1,more-1};
}
public void swap(int[] arr,int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}