【在线编程】数组中出现次数超过一半的数字
【问题描述】
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
【解题思路 & Java实现】
方法一:如果数组中存在超过数组一半的数字,那么数组排序后,这个数字一定出现在数组的中间位置。所以先排序,然后统计中间数字的个数是否大于数组的一半。时间复杂度 O(nlogn)
import java.util.Arrays;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
Arrays.sort(array);
int count = 0;
for(int i = 0; i < array.length; i++) {
if(array[i] == array[array.length/2]) {
count++;
}
}
if(count > array.length/2) {
return array[array.length/2];
} else {
return 0;
}
}
}
方法二:基于快速排序的Partition函数,partition 函数每次能确定一个元素的位置,并返回这个位置,只要partition返回的位置pivot刚好哦为数组的中间下标就可以了。其实与方法一差不多,只是不用把快速排序执行完,只要确定中间下标的元素就可以了。
public class Solution {
public static void main(String[] args) {
int[] array = {1, 2, 3, 2, 4, 2, 5, 2, 3};
System.out.println(MoreThanHalfNum_Solution(array));
}
public static int MoreThanHalfNum_Solution(int[] array) {
int left = 0;
int right = array.length - 1;
int middle = array.length / 2;
int pivot = partition(array, left, right);
while (pivot != middle) {
if (pivot < middle) {
pivot = partition(array, pivot + 1, right);
} else {
pivot = partition(array, left, pivot - 1);
}
}
int target = array[middle];
int count = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] == target) count++;
}
return count > array.length / 2 ? target : 0;
}
public static int partition(int[] array, int left, int right) {
int key = array[left];
while (left < right) {
while (left < right && array[right] >= key) {
right--;
}
array[left] = array[right];
while (left < right && array[left] <= key) {
left++;
}
array[right] = array[left];
}
array[left] = key;
return left;
}
}
方法三:“阵地防守”思想。主元素出现的次数比其他任何元素出现的次数之和还要多。时间复杂度O(n).
第一个数字作为第一个士兵,守阵地;count = 1;
遇到相同元素,count++;
遇到不相同元素,即为敌人,同归于尽,count–;当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,有可能是主元素。
最后判断这个士兵的个数是否大于数组一半。
public class Solution {
public static int MoreThanHalfNum_Solution(int[] array) {
int guard = array[0];
int count = 1;
//通过"阵地防守"法选择最有可能为主元素的数字
for (int i = 1; i < array.length; i++) {
if (count <= 0) {
guard = array[i];
count = 1;
} else {
if (array[i] == guard) {
count++;
} else {
count--;
}
}
}
//计数,验证是否真的为主元素
count = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] == guard) count++;
}
return count > array.length/2 ? guard : 0;
}
}
方法四:借用 HashMap。遍历数组,并存入 HashMap,更新个数,并判断个数是否满足大于数组长度的一半。
import java.util.HashMap;
public class Solution {
public static void main(String[] args) {
int[] array = {1, 2, 3, 2, 4, 2, 5, 2, 3};
System.out.println(MoreThanHalfNum_Solution(array));
}
public static int MoreThanHalfNum_Solution(int[] array) {
HashMap<Integer, Integer> map = new HashMap<>();
int target = 0;
for (int i = 0; i < array.length; i++) {
if (map.containsKey(array[i])) {
map.put(array[i], map.get(array[i]) + 1);
} else {
map.put(array[i], 1);
}
if (map.get(array[i]) > array.length / 2) {
target = array[i];
}
}
return target;
}
}