[路飞]_最大间距

242 阅读3分钟

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

164. 最大间距

题目

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

示例1

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

示例2

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

题解

暴力全排序

找到排序后相邻元素之间最大的差值。最容易想到的思路就是将数组整个排序,根据排序后的结果枚举数组,逐一对比相邻元素值。变量记录相邻元素之差的最大值即可;具体代码如下:

时间复杂度:全排序需要的时间复杂度为O(nlogN),枚举需要的时间复杂度为O(n);所以总体时间复杂度为O(nlogN)

代码

var maximumGap = function (nums) {
  if (nums.length < 2) return 0
  nums.sort((a, b) => a - b)
  let max = 0
  for (let i = 1; i < nums.length; i++) {
    max = Math.max(max, nums[i] - nums[i - 1])
  }
  return max
}

进阶要求

  • 你可以假设数组中所有元素都是非负整数,且数值在 32 位有符号整数范围内
  • 请尝试在线性时间复杂度和空间复杂度的条件下解决此问题

桶排序

假设现在有数组 nums = [3,6,9,1];

  • 数组长度为len=4
  • 数组最大值max = 9
  • 数组最小值min = 1
  • 数组最大间距为 max - min = 8
  • 讲最大间距8均分到len-1份,得到每份间距space = 8/3 (向下取整) = 2;
  • 每份间距为2,长度为8的间距需要 8/2+1 = 5个桶
  • 五个桶分别是[1,2],[3,4],[5,6],[7,8],[9,10];
  • 将数据放入桶中,有数据放数据,没数据设置为0;
  • 得到数据为[ [ 1, 1 ], [ 3, 3 ], [ 6, 6 ], [ 0, 0 ], [ 9, 9 ] ];
    • 解释:桶1的最大数据为1,最小数据为1,
    • 桶2、3类似
    • 桶4表示[7,8]这个区间,因为数组没有7、8这两个值,所以此处是空桶
    • 桶5与桶1、2、3类似
  • 五个桶,每个桶可以装2个数据(间距是2);一共可以装10个数据,但是数组中最大值与最小值之差是8;也就是说必然最少有一个桶是空的; 这句话比较关键,需要理解
  • 将数据放入桶中,必然有一个桶中最大值与下一个非空桶最小值在排序数据相邻;关键
  • 又因为一定存在空桶,必然够空桶左右两个非空桶内数据的差值大于桶内各个数据差值
  • 根据上述思路编辑代码如下

桶排序代码

var maximumGap = function (nums) {
  const len = nums.length;
  if (len < 2) return 0;
  let max = -Infinity;
  let min = Infinity;
  for (let i = 0; i < len; i++) {
    max = Math.max(max, nums[i]);
    min = Math.min(min, nums[i]);
  }
  const space = Math.max(1, Math.floor((max - min) / (len - 1)));
  const bucketLength = Math.floor((max - min) / space) + 1;
  const bucket = [];
  for (let i = 0; i < bucketLength; ++i) {
    bucket[i] = Array(2).fill(0);
  }
  for (let i = 0; i < len; i++) {
    const idx = Math.floor((nums[i] - min) / space);
    if (bucket[idx][0] === 0) {
      bucket[idx][0] = bucket[idx][1] = nums[i];
    } else {
      bucket[idx][0] = Math.min(bucket[idx][0], nums[i]);
      bucket[idx][1] = Math.max(bucket[idx][1], nums[i]);
    }
  }

  let prev = null;
  let result = 0;
  for (let i = 0; i < bucketLength; i++) {
    if (bucket[i][0] === 0) continue;
    if (prev !== null) {
      result = Math.max(result, bucket[i][0] - bucket[prev][1]);
    }
    prev = i;
  }
  return result;
};