//做这道题的时候真的是漏洞百出?
简单的方法
直接排序,检查数组中间的那个元素出现的次数是不是大于1/2*length,复杂度是O(nlogn)
优化的方法
我们首先注意到的是如果一个元素在数组中出现的次数大于一半,那它肯定是这个数组的中位数(这个很好想,比如 {1,2,5,5,5,5,5,8,9},中位数就是5)
上面的方法就是通过排序直接找到中位数,但是是有没有必要做的事情的,就是我们一旦找到了中位数,别的数字的顺序是没有必要去维护的
然后就可以借鉴快排的思想
「 快排中有个叫Partition的函数可以用来随机选取一个数pivot,把所有小于pivot的都放在这个数左边,大于pivot的放在右边,最后返回pivot的下标index 」
如果我们不断使用partition函数就可以找到中位数:
middle = array.length /2
返回的index如果小于middle,说明中位数在大于index的位置,否则在小于index的位置,继续调用partition在更小的区间去找到一个下标等于middle的数,即是中位数
public static int getMiddle(int [] array ) {
int length = array.length;
if(array == null || array.length == 0) return 0;//检测数组是否合法
int middle = length >> 1;
int start = 0;
int end = length - 1;
int index = Partition(array, length, start, end);
while(index != middle){
if(index > middle) index = Partition(array, length, start, index-1);//左半部分去找
else index = Partition(array, length, index + 1, end);//右半部分去找
}
int result = array[middle];
if(checkMoreThanHalf(array, length, result) == false) result = 0;
return result;
}
public static int Partition(int [] data,int length ,int start,int end) {
int swp ;
if(data == null || length <= 0 || start < 0 || end >= length ) return -1;
int index = start + (int) ( Math.random() * (end - start));//随机生成pivot的下标index
swp = data[index]; data[index] = data[end]; data[end] = swp;
int small = start - 1;
for(index = start; index < end; index ++){
if(data[index] < data[end]){
small ++;
if(small != index){
swp = data[index];data[index] = data[small];data[small] = swp;
}
}
}
small ++;
swp = data[small];data[small] = data[end];data[end] = swp;
return small;
}
最主要的是,我第一次写partition的时候没有用随机化,之前学的时候一直觉得随机化是用来防止最坏情况(数组基本有序的时候快排的时间复杂度会降低到n^2),又加上刚刚开始练习java对随机化不是很了解,就没有用,每次直接用最后一个元素作为pivot,没想到直接跑死了
后来才想明白比如
1, 2, 3, 2, 2, 2, 5, 4, 2
=> 1,2,2,2,2,2,3,4,5
如果继续选取最后一个2,下一次返回的index还是这个位置,死循环,然后就死啦
源代码:
import java.util.Arrays;
public class Solution {
public static int MoreThanHalfNum_Solution(int [] array) {
if(array == null || array.length == 0) return 0;
int result = getResult(array);
return result;
}
public static int getResult(int [] array ) {
int length = array.length;
if(array == null || array.length == 0) return 0;
int middle = length >> 1;
int start = 0;
int end = length - 1;
int index = Partition(array, length, start, end);
while(index != middle){
if(index > middle) index = Partition(array, length, start, index-1);
else index = Partition(array, length, index + 1, end);
}
int result = array[middle];
if(checkMoreThanHalf(array, length, result) == false) result = 0;
return result;
}
public static boolean checkMoreThanHalf(int [] data,int length,int number ) {
int times = 0;
for(int d : data) if(d == number) times++;
return (times * 2 > length);
}
public static int Partition(int [] data,int length ,int start,int end) {
int swp ;
if(data == null || length <= 0 || start < 0 || end >= length )
return -1;
int index = start + (int) ( Math.random() * (end - start));
swp = data[index]; data[index] = data[end]; data[end] = swp;
int small = start - 1;
for(index = start; index < end; index ++){
if(data[index] < data[end]){
small ++;
if(small != index){
swp = data[index];data[index] = data[small];data[small] = swp;
}
}
}
small ++;
swp = data[small];data[small] = data[end];data[end] = swp;
// for (int d : data) {
// System.out.print(d+" ");
// }
// System.out.println(" ");
return small;
}
}
方法三
这里就直接把书里面的内容截过来了?
代码:
import java.util.Arrays;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array == null || array.length == 0) return 0;
int number = 0,cnt = 0;
for(int a : array){
if(cnt == 0){
number = a;
cnt = 1;
}
if(a == number) cnt++;
else cnt--;
}
int times = 0;
for(int a : array){
if(a == number) times++;
}
return times * 2 > array.length ? number : 0;
}
public static void main(String[] args) {
int [] a = {1,2,3,5,5,5,5,5,5,7,7};
Solution s = new Solution();
int result = s.MoreThanHalfNum_Solution(a);
System.out.println(result);
}
}