无序数组排序并得到最大间隔

这篇博客介绍了如何在O(n)时间复杂度内解决求解排序数组中相邻元素最大差值的问题。首先,通过计数排序的思想,创建新数组并统计最大连续空值来找到最大间隔;然后,利用桶排序的方法,根据单位区间长度划分桶,并计算桶间最大差值。这两种方法避免了传统排序的高时间复杂度,特别适用于最大值和最小值相差巨大的情况。
摘要由CSDN通过智能技术生成

问题描述

给定一个无序整型数组,求将其排好序后,并得出相邻两个数之间的最大差值。

例如:{1,3,2,5,7,4,13}
排序后{1,2,3,4,5,7,13} 那么最大间隔是6

这个问题大部分人会想到先排序后遍历的解法,但是这个问题要求的时间复杂度是O(n)传统的排序并做不到

解法思路一:运用计数排序的思想

  1. 先求出原数组的最大值Max与最小值Min的区间长度k(k=Max-Min+1)。
  2. 创建一个长度为k的新数组Array。
  3. 遍历原数组,把原数组每一个元素插入到新数组Array对应的位置,比如元素的值为n,则插入到Array[n-min]当中。此时Array的部分位置为空,部分位置填充了数值。
  4. 遍历新数组Array,统计出Array中最大连续出现空值的次数+1,即为相邻元素最大差值。
public static int countSort(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        int maxInterval = 0;
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        int len = nums.length;
        //保存原数组最大值和最小值
        for (int i = 0; i < len; i++) {
            max = Math.max(max, nums[i]);
            min = Math.min(min, nums[i]);
        }
        //新数组长度区间
        int[] newNums = new int[max - min + 1];
        int bucketIndex = 0;
        for (int i = 0; i < len; i++) {
            bucketIndex = (nums[i] - min);
            newNums[bucketIndex] = nums[i];
        }
        int lastMaxBucketValue = 0;
        for (int i = 1; i < newNums.length; i++) {
            //统计出Array中最大连续出现空值的次数
            if (newNums[i] == 0) {
                lastMaxBucketValue++;
                if (lastMaxBucketValue > maxInterval) {
                    maxInterval = lastMaxBucketValue;
                }
            } else {
                lastMaxBucketValue = 0;
            }
        }
        //maxInterval+1即为所求
        return maxInterval + 1;
    }

但是当最大值和最小值相差巨大的时候,浪费了极大的空间,所以我们还要了解解法二

解法思路二:运用桶排序的思想

  1. 先求出原数组从最小值Min到最大值Max的单位区间长度d,d=(Max-Min+n+1)/n(此处运用(a+b+1)/b来获得a/b向上取整的结果)。算出d的作用是为了后续确定各个桶的区间范围划分。
  2. 创建一个长度是N+1的数组Array,数组的每一个元素都是一个List,代表一个桶。
  3. 遍历原数组,把原数组每一个元素插入到新数组Array对应的桶当中,进入各个桶的条件是根据不同的数值区间。由于桶的总数量是N+1,所以至少有一个桶是空的
  4. 遍历新数组Array,计算每一个空桶右端非空桶中的最小值,与空桶左端非空桶的最大值的差,数值最大的差即为原数组排序后的相邻最大差值。(因为还要对每个桶排序才能得到最大值或者最小值,考虑到桶内排序的复杂度,我们可以做两个新数组,一个保存每个桶的最大值,一个保存每个桶的最小值,这样就免去了桶内排序的复杂度提升
public static int bucketSort( int[] nums){
        if(nums == null || nums.length < 2)
            return 0;
        int maxInterval = 0;
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        int len = nums.length;
        //保存原数组最大值和最小值
        for(int i = 0;i < len;i ++ ){
            max = Math.max(max,nums[i]);
            min = Math.min(min,nums[i]);
        }
        int[] maxs = new int[len + 1];
        int[] mins = new int[len + 1];
        int bucketIndex = 0;
        for(int i = 0;i < len;i ++ ){
            bucketIndex = (nums[i] - min) / ((max - min + len + 1)/len);
            maxs[bucketIndex] =  maxs[bucketIndex] == 0 ? nums[i] : Math.max(maxs[bucketIndex],nums[i]);
            mins[bucketIndex] =  mins[bucketIndex] == 0 ? nums[i] : Math.min(mins[bucketIndex],nums[i]);
        }
        int lastMaxBucketValue = maxs[0];
        for(int i = 1;i < len + 1;i ++){
            //获得当前非空桶最小值与上一个非空桶最大值的差值即为所求
            if(mins[i] != 0){
                maxInterval = Math.max(maxInterval,mins[i] - lastMaxBucketValue);
                lastMaxBucketValue = maxs[i];
            }
        }
        return maxInterval;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值