问题:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解决:
① 在之前已经写过了根据数组特点求解的方式,即数组中出现次数超过一半的数字,肯定比其他所有数字出现的次数的和还多,所以可以通过相同加1,不同减1的方式来解决。
② 基于 Partition 函数的 O(n)算法
数组中有一个数字出现的次数超过了数组长度的一半。如果把这个数组排序,那么排序之后位于数组中间的数字一定就是那个出现次数超过数组长度一半的数字。也就是说,这个数字就是统计学上的中位数,即长度为 n 的数组中第 n/2 大的数字。
这种算法是受快速排序算法的启发。在随机快速排序算法中,我们先在数组中随机选择一个数字,然后调整数组中数字的顺序, 使得比选中的数字小数字都排在它的左边,比选中的数字大的数字都排在它的右边。如果这个选中的数字的下标刚好是 n/2,那么这个数字就是数组的中位数。如果它的下标大于 n/2 ,那么中位数应该位于它的左边,我们可以接着在它的左边部分的数组中查找。如果它的下标小于 n/2,那么中位数应该位于它的右边,我们可以接着在它的右边部分的数组中查找。这是一个典型的递归过程。
public class Solution {
public static int MoreThanHalfNum_Solution(int [] array) {
return MoreThanHalfNum_Solution(array,array.length);
}
public static int MoreThanHalfNum_Solution(int[] arr,int len){
int mid = len / 2;
int start = 0;
int end = len - 1;
int index = Partition(arr,len,start,end);
while(index != mid){
if (index > mid){
end = index - 1;
index = Partition(arr,len,start,end);
}else {
start = index + 1;
index = Partition(arr,len,start,end);
}
}
int res = arr[mid];
int count = 0;
for (int i = 0;i < len;i ++){
if (arr[i] == res){
count ++;
}
}
if (count > len / 2){
return res;
}else {
return 0;
}
}
public static int Partition(int[] arr,int len,int start,int end){
int pivot = arr[start];
while (start < end){
while(start < end && arr[end] >= pivot){
end --;
}
arr[start] = arr[end];
while(start < end && arr[start] <= pivot){
start ++;
}
arr[end] = arr[start];
}
arr[end] = pivot;
return end;
}
}