面试题39:数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, 4, 2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
问题分析
大家最容易想到的思路是 数字次数超过一半,则说明排序之后数组中间的数字一定就是所求的数字。
既然是数组,要牵扯到排序,大家一般都会选用经典快速排序或者随机快速排序。随机快速排序由于每次划分的依据是从数组随机选出的,所以数据状况对它的影响减弱,时间复杂度为 O(N*logN),而快速排序受数据状况的影响,时间复杂度差的话为O(n^2)。本文使用的是快速排序,书写比较方便。
其实还有一个比较有意思,而且非常好的算法思想,被描述为阵地攻守的思想:
第一个数字作为第一个士兵,守阵地;count = 1;
遇到相同元素,count++;
遇到不相同元素,即为敌人,同归于尽,count--;当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,有可能是主元素。
再加一次循环,记录这个士兵的个数看是否大于数组一般即可。
也就是数字次数超过一半,则说明:该数字出现的次数比其他数字之和还多
遍历数组过程中保存两个值:一个是数组中某一数字,另一个是次数。遍历到下一个数字时,若与保存数字相同,则次数加1,反之减1。若次数=0,则保存下一个数字,次数重新设置为1。由于要找的数字出现的次数比其他数字之和还多,那么要找的数字肯定是最后一次把次数设置为1的数字。
问题解答
思路一(不推荐)
// 表示输入是否有效
boolean isInputInvalid = true;
// 快速排序
public int MoreThanHalfNum(int [] array) {
if(array==null ||array.length <= 0) {
return 0;
}
int low=0;
int high=array.length-1;
int index=partition(array, low, high);
while(index != array.length>>1){
if(index < array.length>>1 ){
low = index+1;
index = partition(array,low,high);
} else {
high = index-1;
index=partition(array,low,high);
}
}
//判断次数是否超过一半
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){
isInputInvalid=false;
return num;
}
return 0;
}
private int partition(int[] array,int low ,int high){
int pivotKey=array[low];
while(low < high){
while(low < high && array[high] >= pivotKey) {
high--;
}
int temp=array[low];
array[low]=array[high];
array[high]=temp;
while(low < high && array[low] <= pivotKey) {
low++;
}
temp=array[low];
array[low]=array[high];
array[high]=temp;
}
return low;
}
思路二(推荐)
// 表示输入是否有效
boolean isInputInvalid = true;
public int MoreThanHalfNum(int [] array) {
if(array==null || array.length <= 0) {
return 0;
}
int num=array[0];
int count = 1;
for(int i=1;i<array.length;i++){
if(count == 0) {
num=array[i];
count++;
}
else if(array[i] == num) {
count++;
}
else {
count--;
}
}
if(count > 0){
int times=0;
for(int i=0;i<array.length;i++){
if(array[i] == num){
times++;
}
}
if(times*2 > array.length){
isInputInvalid=false;
return num;
}
}
return 0;
}