leedcode164.最大间距

题目描述

给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。

如果数组元素个数小于2,则返回0。

示例1:

输入:[3,6,9,1]
输出:3
解释:排序后的数组是[1,3,6,9],其中相邻元素(3,6)(6,9)之间存在最大差值3

示例2:

输入:[10]
输出:0
解释:数组元素个数小于2,因此返回0

题目解析

首先题目中要求对数组进行排序,排序可以使用java中已经封装好的sort函数,但题目要求时间复杂度为线性阶。
由于这里的数据是有范围的,随意我们可以使用一种不经常使用的一种排序方法----- 基数排序
首先简单来讲讲基数排序这个算法,基数代表数组中的每个元素,我们可以先设置一个数组,该数组的下标为元素值,该数组下标所对应的值存储的是该元素的个数。
因为基数排序使用的范围有限,所以我们一般不使用,但该排序算法在解决一些具有范围限制的问题上,会起到关键性作用,排序算法时间复杂度为O(n)。

代码解析

class Solution {
private class Bucket {
    int min = Integer.MAX_VALUE;
    int max = Integer.MIN_VALUE;
}

public int maximumGap(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for (int i : nums) {
            min = Math.min(min, i);
            max = Math.max(max, i);
        }
        
        // 分配桶的长度和个数是桶排序的关键
        // 在 n 个数下,形成的两两相邻区间是 n - 1 个,比如 [2,4,6,8] 这里
        // 有 4 个数,但是只有 3 个区间,[2,4], [4,6], [6,8]
        // 因此,桶长度 = 区间总长度 / 区间总个数 = (max - min) / (nums.length - 1)
        int bucketSize = Math.max(1, (max - min) / (nums.length - 1));
        
        // 上面得到了桶的长度,我们就可以以此来确定桶的个数
        // 桶个数 = 区间长度 / 桶长度
        // 这里考虑到实现的方便,多加了一个桶,为什么?
        // 还是举上面的例子,[2,4,6,8], 桶的长度 = (8 - 2) / (4 - 1) = 2
        //                           桶的个数 = (8 - 2) / 2 = 3
        // 已知一个元素,需要定位到桶的时候,一般是 (当前元素 - 最小值) / 桶长度
        // 这里其实利用了整数除不尽向下取整的性质
        // 但是上面的例子,如果当前元素是 8 的话 (8 - 2) / 2 = 3,对应到 3 号桶
        //              如果当前元素是 2 的话 (2 - 2) / 2 = 0,对应到 0 号桶
        // 你会发现我们有 0,1,2,3 号桶,实际用到的桶是 4 个,而不是 3 个
        // 透过例子应该很好理解,但是如果要说根本原因,其实是开闭区间的问题
        // 这里其实 0,1,2 号桶对应的区间是 [2,4),[4,6),[6,8)
        // 那 8 怎么办?多加一个桶呗,3 号桶对应区间 [8,10)
        Bucket[] buckets = new Bucket[(max - min) / bucketSize + 1];
        
        for (int i = 0; i < nums.length; ++i) {
            int loc = (nums[i] - min) / bucketSize;
            
            if (buckets[loc] == null) {
                buckets[loc] = new Bucket();
            }
            
            buckets[loc].min = Math.min(buckets[loc].min, nums[i]);
            buckets[loc].max = Math.max(buckets[loc].max, nums[i]);
        }
        
        int previousMax = Integer.MAX_VALUE; int maxGap = Integer.MIN_VALUE;
        for (int i = 0; i < buckets.length; ++i) {
            if (buckets[i] != null && previousMax != Integer.MAX_VALUE) {
                maxGap = Math.max(maxGap, buckets[i].min - previousMax);
            }
            
            if (buckets[i] != null) {
                previousMax = buckets[i].max;
                maxGap = Math.max(maxGap, buckets[i].max - buckets[i].min);
            }
        }
        
        return maxGap;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值