面试题29. 数组中出现次数超过一半的数字

时间:2022-03-09 11:02:35

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0

思路1:

采用“抵消”的思路,已知有一个数出现的次数超过一半,那么把它和数组中其他数相互抵消,最后剩下的一定是这个数。

为此,设置两个变量result 和count,result记录当前出现次数最多的数字;count记录该数字出现的次数。两者均初始化为0。

从头遍历数组:

  • 如果count == 0,则把当前数字赋值給result
  • 如果下一个数字与result相等,则count++,反之count–。

遍历结束后:

  • 如果count < 1, 说明大于一半的数不存在,函数返回0结束;
  • 否则,再次遍历数组,判断当前的result是否出现次数大于一半。

这么做的原因在于:假设当前的数组是[5,2,3],遍历到3时,result = 3;count = 1;虽然count = 1,但3出现的次数没有超过一半。所以不能直接返回3。

整个过程,result和count的值如下:

面试题29. 数组中出现次数超过一半的数字

上述思路的复杂度是O(2n),Java代码如下:

public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
int count = 0, result = 0;
for(int i = 0; i < array.length; i++) {
if(count == 0) {
result = array[i];
count = 1;
}else {
count = array[i] == result ? count + 1 : count - 1;
}
}
if(count < 1) return 0;
count = 0;
for(int i = 0; i < array.length; i++) {
if(array[i] == result) {
count++;
}
}
return count >= (array.length / 2 + 1) ? result : 0;
}
}

思路2:

如果把数组排序,我们发现:
数组中出现次数超过一半的数字,刚好等于数组的中位数,所以只要找到了中位数就行。

利用快排Partition的思想
首先在数组中随机选择一个数字,然后把比它小的数字移到它的左边,把比它大的数字移到右边。全部移动完后:

  • 如果这个数字刚好处于数组的中间,那么中位数就是它。
  • 如果这个数字在中间偏右,那么中位数在它左边,继续对左边查找
  • 如果这个数字在中间偏左,那么中位数在它右边,继续对右边查找

    面试题29. 数组中出现次数超过一半的数字