LeetCode题练习与总结:最大间距--164

173 篇文章 0 订阅
109 篇文章 0 订阅

一、题目描述

给定一个无序的数组 nums,返回 数组在排序之后,相邻元素之间最大的差值 。如果数组元素个数小于 2,则返回 0 。

您必须编写一个在「线性时间」内运行并使用「线性额外空间」的算法。

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 10^5
  • 0 <= nums[i] <= 10^9

二、解题思路

  1. 确定桶的大小:首先找出数组中的最大值和最小值,计算出差值。这个差值将用于确定桶的大小。每个桶的容量是(最大值 - 最小值) / (数组长度 - 1)

  2. 创建桶:根据上述计算出的桶大小,创建足够的桶。每个桶只存储该区间内的最大值和最小值。

  3. 分配数字到桶中:遍历数组,将每个数字分配到相应的桶中。对于每个桶,只需要记录该桶内的最大值和最小值,因为最大差值只可能出现在相邻桶之间。

  4. 找出最大差值:遍历桶,计算相邻非空桶之间的最小值之差,最大的那个差值就是答案。

三、具体代码

class Solution {
    public int maximumGap(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }

        int min = nums[0];
        int max = nums[0];
        for (int num : nums) {
            min = Math.min(min, num);
            max = Math.max(max, num);
        }

        int bucketSize = Math.max(1, (max - min) / (nums.length - 1));
        int bucketCount = (max - min) / bucketSize + 1;

        int[] bucketMin = new int[bucketCount];
        int[] bucketMax = new int[bucketCount];
        Arrays.fill(bucketMin, Integer.MAX_VALUE);
        Arrays.fill(bucketMax, Integer.MIN_VALUE);

        for (int num : nums) {
            int index = (num - min) / bucketSize;
            bucketMin[index] = Math.min(bucketMin[index], num);
            bucketMax[index] = Math.max(bucketMax[index], num);
        }

        int maxGap = 0;
        int previousMax = bucketMax[0];
        for (int i = 1; i < bucketCount; i++) {
            if (bucketMin[i] != Integer.MAX_VALUE) {
                maxGap = Math.max(maxGap, bucketMin[i] - previousMax);
                previousMax = bucketMax[i];
            }
        }

        return maxGap;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 遍历数组以找到最大值和最小值:这一步的时间复杂度是O(n),其中n是数组的长度,因为我们需要遍历整个数组一次。

  • 初始化桶:初始化桶的时间复杂度是O(1),因为桶的数量与数组的长度成线性关系,但是这个操作是常数时间的。

  • 分配数字到桶中:这一步的时间复杂度也是O(n),因为我们再次遍历数组,并将每个元素放入相应的桶中。每个操作是常数时间的。

  • 找出最大差值:这一步的时间复杂度是O(m),其中m是桶的数量。在最坏的情况下,m可以接近n,但是通常情况下,m会远小于n,因为桶的大小是由数组的长度决定的。

综上所述,整个算法的时间复杂度是O(n),因为所有的步骤都是线性的,没有步骤会超过O(n)的时间复杂度。

2. 空间复杂度
  • 桶数组:我们需要两个数组来存储每个桶的最小值和最大值,这两个数组的长度与桶的数量相同。在最坏的情况下,桶的数量可以接近数组的长度n,因此空间复杂度是O(n)。

  • 其他变量:除了桶数组之外,我们只使用了几个额外的变量来存储最小值、最大值、桶大小等,这些变量的空间占用是常数的,因此可以忽略不计。

综合以上分析,整个算法的空间复杂度是O(n),因为我们需要存储每个桶的最小值和最大值,这需要与数组长度成线性关系的额外空间。

五、总结知识点

  1. 线性时间复杂度算法设计:代码的核心在于寻找一个线性时间复杂度的算法来解决问题,这是通过对数组进行一次遍历来实现的。

  2. 桶排序(Bucket Sort):虽然代码并不是为了对数组进行完全排序,但是它使用了桶排序的思想。桶排序是一种将元素分配到有限数量的桶中,然后对每个桶进行单独排序的算法。在这个问题中,我们只关心每个桶的最大值和最小值,因为最大差值只能出现在相邻桶之间。

  3. 空间换时间:通过使用额外的空间(桶数组)来减少时间复杂度。这是一种常见的编程技巧,在不能牺牲时间复杂度的场合特别有用。

  4. 数组操作:代码中使用了数组的填充(Arrays.fill)和遍历等基本操作。

  5. 数学计算:计算桶的大小和数量涉及到基本的数学运算,如除法和加法。

  6. 边界条件处理:代码首先检查输入数组的长度,如果长度小于2,则直接返回0,这是因为长度小于2的数组不存在相邻元素。

  7. 最小值和最大值的初始化:在遍历数组之前,将最小值和最大值初始化为数组的第一个元素,这是一种常见的初始化技巧。

  8. 遍历和比较:代码中多次使用遍历和比较操作来找到最小值、最大值以及最大差值。

  9. 整数除法:在计算桶的大小时,使用了整数除法,这会向下取整,确保每个桶的大小合适。

  10. 无穷大和无穷小值的处理:使用Integer.MAX_VALUEInteger.MIN_VALUE来初始化桶的最小值和最大值,这是一种常见的做法,以便在后续的比较中正确地识别出桶中的实际最小值和最大值。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值