思路:
1、HashMap中存储个元素次数,之后排序,统计出最大的
2、中位数思想,快排一到两次,判断中间的数字是否为目标值
3、利用数组特性,逐个遍历,相同的次数加1,不同的减1,count为负数时,重置数据
代码:
package com.datastructure.array;
/**
* 找出数组中出现次数超过一半的数字
*/
public class NumberOverHalf {
/**
* 快排思想
*
*
*/
public static int getNumberByPartition(int[] arr) {
int len = arr.length;
int mid = getMiddle(arr, 0, len-1);
while (mid != len/2) {
if (mid < len/2) {
mid = getMiddle(arr, mid + 1, len-1);
} else {
mid = getMiddle(arr, 0, mid);
}
}
int num = arr[mid];
// 判断数据的出现次数 是否真正超过一半
int numCount = 0;
for (int i = 0; i< len; i++) {
if (arr[i] == num) {
numCount++;
}
}
// 无出现次数大于一半的数
if (numCount < len/2) {
return -1;
}
return num;
}
private static int getMiddle(int arr[], int low, int high) {
int base = arr[low];
while (low < high) {
while ( low < high && base <= arr[high]) {
high--;
}
arr[low] = arr[high];
while ( low < high && base >= arr[low]) {
low++;
}
arr[high] = arr[low];
}
// 基准值左侧小于基准值,右侧大于基准值
arr[low] = base;
return low;
}
/**
* 数组中该数字出现次数超过一半,
* 若遍历数组,记录该元素,遇到相同的就次数加1,不同的减一,为负数时,更换元素,
* 则最后一个必然是出现次数超过一半的数字
*
*
*/
public static int getNumberOverHalf(int[] arr) {
if (arr == null || arr.length <= 0) {
return -1;
}
int len = arr.length;
int curNum = arr[0];
int count = 1;
for (int i=1; i<len; i++) {
// 相同则增加count
if (arr[i] == curNum) {
count++;
} else {
// 不同则减少
if (count > 0) {
count --;
// 出现负值情况则重置数据
} else {
curNum = arr[i];
count = 1;
}
}
}
// 判断数据的出现次数 是否真正超过一半
int numCount = 0;
for (int i = 0; i< len; i++) {
if (arr[i] == curNum) {
numCount++;
}
}
// 无出现次数大于一半的数
if (numCount < len/2) {
return -1;
}
return curNum;
}
public static void main(String[] args) {
int[] arr1 = new int[]{1,4,3,4,4,4,5,6,4,4,4,1};
System.out.println(getNumberByPartition(arr1));
int[] arr2 = new int[]{1,4,3,1,5,6,4,4};
System.out.println(getNumberByPartition(arr2));
int[] arr3 = new int[]{1,4,3,4,4,4,5,6,4,4,4,1};
System.out.println(getNumberOverHalf(arr3));
int[] arr4 = new int[]{1,4,3,1,5,6,4,4};
System.out.println(getNumberOverHalf(arr4));
}
}
参考:
数组中出现次数超过一半的数字:https://blog.csdn.net/derrantcm/article/details/46736859