问题:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
分析:看到此题第一反应就是将数组中的数字进行排序,然后统计数字出现的次数。排序的时间复杂度为O(nlogn)。
从另一个角度出发,数组中有一个数字出现的次数大于数组长度的一半,也就是说它出现的次数比其他数字出现次数之和还要多。因此可以在遍历数组的时候保存两个值:(1)保存数组中的值;(2)保存数字出现的次数。
步骤:(1)当遍历的下一个数字与之前保存的数字不同时, 将次数减1;
(2)当遍历的下一个数字与之前保存的数字相同时, 将次数加1;
(3)当次数为0时,保存下一个遍历的数字,并且次数置为1。
由于我们要找的数字比其他数字出现的次数之和还要多,那么要找的数字肯定是最后一次将次数置为1的数字。
package com.wyl;
/**
* 寻找数组中出现次数超过数组长度一般的数组
* @author wyl
*
*/
public class MoreThanHalfNum {
/**
* 遍历数组的时候保存两个值:一个是数组中的值,一个为次数
* 遍历数组,如果遍历的下一个数字和之前保存的值不一样时, 次数减1;
* 如果和之前保存的值相同的时候,次数加1;
* 如果次数为0时,保存下一个数字,并且次数设为1
* */
public int moreThanHalfNum(int[] array, int length){
if(array == null || length <= 0){ //输入的数组非法
return 0;
}
int number = 0; //保存数组中的一个数字
int count = 0; //保存数字出现的次数
for(int i=0;i<length;i++){
if(count == 0){
number = array[i];
count = 1;
}else if(array[i] == number){
count++;
}else{
count-- ;
}
}
if(!checkNumMoreThanHalf(array, length, number)){
return 0;
}
return number;
}
/**
* 检查数字number在数组array中出现的次数是否大于一般
* @param array
* @param length
* @param number
* @return
*/
private boolean checkNumMoreThanHalf(int[] array, int length, int number) {
// TODO Auto-generated method stub
boolean isMoreThanHalf = true;
int count = 0;
for(int i=0;i<length;i++){
if(array[i] == number){
count++;
}
}
if(count*2 <= length){
isMoreThanHalf = false;
}
return isMoreThanHalf;
}
public static void main(String[] args) {
MoreThanHalfNum moreThanHalfNum = new MoreThanHalfNum();
int[] a = {1,0,3,0,0,0,5,4,0,3};
int num = moreThanHalfNum.moreThanHalfNum(a, a.length);
System.out.println(num);
}
}