[路飞]_LeetCode_164. 最大间距

198 阅读1分钟

「这是我参与2022首次更文挑战的第33天,活动详情查看:2022首次更文挑战

题目

给定一个无序的数组 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 <=105次方
0 <= nums[i] <= 109次方

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ma… 著作权归领扣网络所有。

解题思路

因为题目对时间、空间复杂度有要求,所以不能用快速、归并排序。这里使用基数排序,基数排序是稳定的排序,并且可以保证时间和空间复杂度是O(n)。

处理过程如下:

  1. 首先对个位数字进行计数;
  2. 再对计数结果计算前缀和,得到0-9存放的最大下标;
  3. 将数字从右往左根据下标写入临时数组中;
  4. 将临时数组中的元素写回原数组中;
  5. 重复高一位做以上操作;

代码实现

var maximumGap = function(nums) {
    //数组中只有一个元素或没有元素时没有最大间距
    if (nums.length < 2) return 0

    const len = nums.length
    const temp = new Array(len)
    const max = Math.max(... nums)
    let exp = 1

    //如果最大数字大于等于第 exp,则对 exp 为进行排序
    while(max >= exp) {
        //声明计数结果数组,并将每个元素初始化为 0
        const cnt = new Array(10).fill(0)
        
        //对 exp 位进行计数,将结果放在 cnt 数组中
        for (const x of nums) {
            //计算 exp 位的值
            const digit = Math.floor(x / exp) % 10
            cnt[digit]++
        }
        
        //计算前缀和
        for (let i = 1; i < 10; i++) cnt[i] += cnt[i - 1]
        
        //将 exp 位排序的结果放入 temp 数组中,从后往前放入
        for (let i = len - 1; i >= 0; i--) {
            //计算 exp 位的值
            const digit = Math.floor(nums[i] / exp) % 10
            
            //将 nums[i] 放入到 cnt[digit] 位上,并且 cnt[digit] 减1
            temp[--cnt[digit]] = nums[i]
        }
        
        //将 temp 数组中已排序的元素更新到 nums 数组中
        nums = [...temp]

        //对高一位进行计数排序操作
        exp *= 10
    }

    let ans = 0
    //遍历排序后的数组,计算相邻元素之间的差,取其中最大的差
    for (let i = 1; i < len; i ++) {
        ans = Math.max(ans, nums[i] - nums[i - 1])
    }
    return ans
};

如有错误欢迎指出,欢迎一起讨论!