例题1

  给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度为O(N),且要求不能用非基于比较的排序。

(1)准备桶,如果一个数组中有N个数,就准备N+1个桶,先遍历整个数组找到最小值和最大值,如果最小值和最大值相等,说明整个数组就只有一种数,最大差值是0。如果最小值和最大值不等,我们将最小值放在第0号桶里,最大值放在N号桶里。将(max-min)这个范围等分成N+1份,那么中间必定存在一个空桶,一个数属于哪个范围就放在哪个桶里。比如一个数组有9个数, 准备10个桶,假设数组中最小值是0,最大值是9,那么0就放在0号桶,9放在9号桶,中间的数放在中间的桶。相邻两数可能来自同一个桶,也可能来自相邻的桶,最大差值一定不来自相同桶的数。最大差值是来自:后一个桶的最小值和前一个桶的最大值之间的 ,那么差值一定是来自这里面的差值。桶只用来记录进入到桶的最大值和最小值。最大差值不一定是空桶两侧来自非空桶的情况。

package com.cisco.www.sort;

public class MaxGap {
    public static int maxGap(int[] nums){
        if(nums==null||nums.length<2){
            return 0;
        }
        int len = nums.length;
        //最小设置为系统最大
        int min = Integer.MAX_VALUE;
        //最大设置为系统最小
        int max = Integer.MIN_VALUE;
        //先遍历整个数组,找打最小值和最大值
        for(int i= 0 ;i<len;i++){
            min = Math.min(min,nums[i]);
            max = Math.max(max,nums[i]);
        }
        //如果最小值和最大值相等,那么久返回0,最大差值是0.
        if(min==max){
            return 0;
        }
        //设计这三个数组,是为了记录出三个桶是否有值,最大值,最小值
        boolean[] hasNum = new boolean[len+1];
        int[] maxs = new int[len+1];
        int[] mins = new int[len+1];
        int bid = 0 ;
        for(int i= 0 ;i<len;i++){
            //确定当前数去几号桶
            bid = bucket(nums[i],len,min,max);
            mins[bid] = hasNum[bid]?Math.min(mins[bid],nums[i]):nums[i];
            maxs[bid]=hasNum[bid]?Math.max(maxs[bid],nums[i]):nums[i];
            hasNum[bid] = true;
        }
        int res = 0 ;
        int lastMax = maxs[0];
        int i= 1;
        for(;i<len;i++){
            if(hasNum[i]) {
                res = Math.max(res, mins[i] - lastMax);
                lastMax = maxs[i];
            }
        }
        return res;
    }

    private static int bucket(int num, int len, int min, int max) {
        return (int)((num-min)*len/(max-min));
    }
}

 

posted @ 2019-06-19 07:06  stone1234567890  阅读(199)  评论(0编辑  收藏  举报