剑指Offer_28_数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解题思路
-
解法1
超过一半的数据一定位于数组的中位数位置,故可以使用基于快速排序的查找。在随机快速排序算法中,我们先在数组中随机选择一个数字,然后调整数组中数字的顺序,使得比选中的数字小数字都排在它的左边,比选中的数字大的数字都排在它的右边。如果这个选中的数字的下标刚好是n/2,那么这个数字就是数组的中位数。如果它的下标大于n/2 ,那么中位数应该位于它的左边,我们可以接着在它的左边部分的数组中查找。如果它的下标小于n/2 , 那么中位数应该位于它的右边,我们可以接着在它的右边部分的数组中查找。找到中位数后,还需要判断,该数是否超过数组长度的一半。 -
解法2
数组中有一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现次数的和还要多。因此我们可以考虑在遍历数组的时候保存两个值: 一个是数组中的一个数字, 一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加 1 ;如果下一个数字和我们之前保存的数字,不同,则次数减 1 。如果次数为霉,我们需要保存下一个数字,并把次数设为 1 。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。找到数后,还需要判断,该数是否超过数组长度的一半。
实现
- 解法1
import java.util.Random;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if (array == null || array.length <= 0) return 0;
int re = recursion(array, 0, array.length-1);
//判断是否超过一半
int count = 0;
for (int i = 0; i < array.length; i++){
if (array[i] == re) count++;
}
if (count>array.length/2) return re;
return 0;
}
private int recursion(int[] array, int start, int end) {
int par = partion(array, start, end);
int half = array.length / 2;
if (par == half) return array[par];
else if (par < half){
return recursion(array, par+1, end);
}else {
return recursion(array,start,par-1);
}
}
private int partion(int[] array, int start, int end) {
if (start > end) return 0;
Random r = new Random();
int rd = r.nextInt(end- start +1) + start;
int tmp = array[rd];
array[rd] = array[end];
array[end] = tmp;
int index = -1;
for (int i = 0; i < end; i++){
if (array[i] <= array[end]){
index++;
if (index != i){
tmp = array[index];
array[index] = array[i];
array[i] = tmp;
}
}
}
tmp = array[++index];
array[index] = array[end];
array[end] = tmp;
return index;
}
}
- 解法2
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if (array == null || array.length <= 0) return 0;
int re = getLastRemain(array);
//判断是否超过一半
int count = 0;
for (int i = 0; i < array.length; i++){
if (array[i] == re) count++;
}
if (count>array.length/2) return re;
return 0;
}
private int getLastRemain(int[] array) {
int now = array[0];
int times = 1;
for (int i = 1; i < array.length; i++){
if (times == 0){
now = array[i];
times = 1;
}else {
if (array[i] == now) times ++;
else {
times--;
}
}
}
return now;
}
}