题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解题思路分析
- 首先很明显的一个方法,先将数组排序,因为如果存在这样一个数的话,那么这个数一定在中间,然后检查它是不是出现次数超过了一半
- 同样还是基于上面的分析,可以使用我们前面用过的partition方法,找出下标在n/2的那个数再检验其出现次数是否超过了一半
- 还有一种方法就是,如果存在这个数的话,那么它出现的次数比其他的所有的数出现的次数都多,那么我们在遍历数组的时候保存两个值,一个是数组中的一个数字,另一个是次数。当下一个数不是保存起来的数的时候,我们将次数-1,如果次数减到了0,那么我们就保存下一个数,因为我们要找的数出现的次数比其他的数的总和还多,所以它一定是最后把次数置为1的那个数
代码实现
- partition思想
public int moreHalfNum(int[] array) {
if (array == null || array.length <= 0) {
return 0;
}
int start = 0, end = array.length - 1;
int index = partition(array, start, end);
int middle = array.length / 2;
while (index != middle) {
if (index > middle) {
end = index - 1;
index = partition(array, start, end);
} else {
start = index + 1;
index = partion(array, start, end)
}
}
return checkMoreThanHalf(array, array[index]) ? array[index] : 0;
}
private int partition(int[] array, int start, int end) {
int base = array[start], i = start, j = end;
while (i < j) {
while (i < j && array[j] > base) {
j--;
}
if ( i < j) {
array[i] = array[j];
i++;
while (i < j && array[i] < base) {
i++;
}
if (i < j) {
array[j] = array[i];
j--;
}
}
}
array[i] = base;
return i;
}
private boolean checkMoreThanHalf(int[] nums, int k) {
int times = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == k) {
times++;
}
}
return times * 2 > nums.length;
}
- 另外一种思想
public int moreHalfNum(int[] array) {
if (array == null || array.length <= 0) {
return 0;
}
int result = array[0], times = 1;
for (int i = 1; i < length; i++) {
//如果times == 0,就重新保存数字
if (times == 0) {
result = arary[i];
} else if (result == array[i]){//相等则times++
times++;
} else {//否则times--
times--;
}
}
return checkMoreThanHalf(array, result) ? resul : 0;
}
private boolean checkMoreThanHalf(int[] nums, int k) {
int times = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == k) {
times++;
}
}
return times * 2 > nums.length;
}