给定一个无序的数组 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 <= 1050 <= nums[i] <= 109
方法二:基于桶的算法
思路与算法
设长度为 N 的数组中最大值为 max,min,则不难发现相邻数字的最大间距不会小于 ⌈(max−min)/(N−1)⌉。
为了说明这一点,我们使用反证法:假设相邻数字的间距都小于 ⌈(max−min)/(N−1)⌉,并记数组排序后从小到大的数字依次为 A 1 ,A 2 ,...,A N ,则有
A N −A 1
=(A N −A N−1 )+(A N−1 −A N−2 )+...+(A 2 −A 1 ) <⌈(max−min)/(N−1)⌉+⌈(max−min)/(N−1)⌉+...+⌈(max−min)/(N−1)⌉ <(N−1)⋅⌈(max−min)/(N−1)⌉=max−min
但根据 A 1 ,A N 的定义,一定有 A 1 =min,且 A N =max,故上式会导出矛盾。
因此,我们可以选取整数 d=⌊(max−min)/(N−1)⌋<⌈(max−min)/(N−1)⌉。随后,我们将整个区间划分为若干个大小为 d 的桶,并找出每个整数所在的桶。根据前面的结论,能够知道,元素之间的最大间距一定不会出现在某个桶的内部,而一定会出现在不同桶当中。
因此,在找出每个元素所在的桶之后,我们可以维护每个桶内元素的最大值与最小值。随后,只需从前到后不断比较相邻的桶,用后一个桶的最小值与前一个桶的最大值之差作为两个桶的间距,最终就能得到所求的答案。
代码如下:
class Solution {
fun maximumGap(nums: IntArray): Int {
val n = nums.size
// 少于两个数不用比较
if (n < 2) return 0
val minVal = nums.min()
val maxVal = nums.max()
// 桶区间大小因子d
val d = maxOf(1, (maxVal - minVal) / (n - 1))
// 在目标数组中需要划分的 桶 的个数, +1是为了消除d取整前的小数部分带来的误差(注意运算顺序)
val bucketSize = (maxVal - minVal) / d + 1
// 创建二维数组,每个桶初始化为 [-1, -1]
// 存储 (桶内最小值,桶内最大值) 对, (-1, -1) 表示该桶是空的
val bucket = Array(bucketSize) { IntArray(2) { -1 } }
for (num in nums) {
// 通过此运算用来判断当前元素属于哪个桶区间
val idx = (num - minVal) / d
// 若区间为空,则此元素是第一次进来,则最大值和最小值都是它
if (bucket[idx][0] == -1) {
bucket[idx][0] = num
bucket[idx][1] = num
} else {
// 若区间存在其他元素,则开始下面比较
// 当前元素与此桶区间的最小值比较,若比最小值还小,就把最小值替换成当前元素值
bucket[idx][0] = minOf(bucket[idx][0], num)
// 当前元素与此桶区间的最大值比较,若比最大值还大,就把最大值替换成当前元素值
bucket[idx][1] = maxOf(bucket[idx][1], num)
}
}
// 目标值
var result = 0
// 上一个下标
var preIndex = -1
// 开始遍历每个桶列表
for (i in 0..<bucketSize) {
// 判断当前桶区间是否为空,空则跳出
if (bucket[i][0] == -1) continue
// 判断上一个下标是否为空,即是否第一次循环
if (preIndex != -1) {
/*
* 计算上一个桶区间的最大值,与当前桶区间的的最小值的差
* 然后与ret目标值比较,取最大值然后替换ret值
*/
result = maxOf(result, bucket[i][0] - bucket[preIndex][1])
}
// 上一个下标自增
preIndex = i
}
return result
}
}