题目:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在这个数组中出现了5次,超过数组 长度的一半,因此输出2
分析:
若一个数组中有一个数字出现了数组长度的一半以上,则必是这个数组的中位数
方法一:最简单粗暴,将数组排序,找出中位数, 时间复杂度为O(nlog(n))
public int Method1(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
方法二:
基于Partition函数
* 随机选择一个数,比它小的都在这个数的左边,比它大的都在这个数的右边。
* 若这个数在排完之后的次序正好为n/2,那就是这个数,若不是。则在n/2的左边或者右边查找
public int Method2(int[] nums) {
int index = Partition(nums, 0, nums.length - 1);
int start = 0;
int end = nums.length - 1;
while(index != nums.length /2) {
if(index < nums.length /2) {
start = index + 1;
index = Partition(nums, start, end);
}else {
end = index - 1;
index = Partition(nums, start, end);
}
}
return nums[index];
}
private int Partition(int[] nums, int start, int end) {
if(start<0 || end >= nums.length) {
return -1;
}
int small = start - 1; //作用是用来记录比末尾值还要小的值应该在的位置
for(int i = start; i <= end; i++) {
if(nums[i] < nums[end]) {
small++;
if(small != i) {
int temp = nums[small];
nums[small] = nums[i];
nums[i] = temp;
}
}
}
/*
* 把末尾值放在他应该在的地方去
*/
small++;
int temp = nums[end];
nums[end] = nums[small];
nums[small] = temp;
return small;
}
方法三:
采取一种类似投票的思路:由于存在一个数超过一半次数
因此,从0位次开始,第一个数字出现,记录该数字,并记录该数字出现的次数。
若下一个数字和上一个数字不一样,times–。且上一个数字的出现次数为0次了。则换数字
public int Method3(int[] nums) {
int times = 1;
int result = nums[0];
for(int i = 1; i < nums.length; i++) {
if(times == 0) {
result = nums[i];
times = 1;
}else {
if(nums[i] != result) {
times--;
}else {
times++;
}
}
}
return result;
}