【剑指offer】数组中出现次数大于数组一半的元素

//做这道题的时候真的是漏洞百出?

简单的方法

直接排序,检查数组中间的那个元素出现的次数是不是大于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);
    }
 
     
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值