1. 问题描述:
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。
如果数组元素个数小于 2,则返回 0。
示例 1:
输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
示例 2:
输入: [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。
2. 问题分析:
- 对于本问题,最直观的方法就是对数组排序,然后逐一进行作差比较,找出最大间距,但是暴力法的时间复杂度太大,不建议采用;
- 在这里为大家提供一个“桶排序”的方法,该方法的时间复杂度为O(n);
- 我们需要解决两个问题:确定“桶”的个数,确定“桶”中元素的个数。首先,我们需要找到给定数组的最大值max和最小值min,确定出最小值到最大值之间的数值个数(max-min+1)。由于“桶”排序比较的是前一个“桶”的最大值和后一个“桶”的最小值,我们可以忽略给定数组的最小值和最大值,将其他元素分配到各个“桶”中。除去最大值和最小值,我们最少需要n-1个“桶”(n为给定数组的元素个数,为了保证“桶”内部的最大间距小于两个“桶”之间的最大间距)。其次,我们需要确定每个“桶”中元素的个数interval = (max - min) /(n-1),这里如果除不尽的话,我们 interval 可以向上取整。必须保证每个数都能放进“桶”里。通过 (nums[i] - min) / interval 即可得到当前数字应该放到的箱子编号。
- 我们通过比较前一个“桶”的最大值和后一个“桶”的最小值来找到最大的间距。
3. 代码实现:
class Solution {
public int maximumGap(int[] nums) {
if(nums == null || nums.length <= 1)
return 0;
int n = nums.length;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for(int i = 0; i < n; i++) {
if(min > nums[i]) min = nums[i];
if(max < nums[i]) max = nums[i];
}
if(max == min) return 0;
int bucketMin[] = new int[n-1];
int bucketMax[] = new int[n-1];
Arrays.fill(bucketMin, Integer.MAX_VALUE);
Arrays.fill(bucketMax,-1);
int interval = (max-min+1)/(n-1) + 1;
for(int i = 0; i < n; i++) {
if(nums[i] == min || nums[i] == max) continue;
int index = (nums[i] - min)/interval;
bucketMax[index] = Math.max(bucketMax[index],nums[i]);
bucketMin[index] = Math.min(bucketMin[index],nums[i]);
}
int maxGap = 0;
int preMax = min;
for(int i = 0; i < n-1; i++) {
if(bucketMax[i] == -1) continue;
maxGap = Math.max(maxGap,bucketMin[i] - preMax);
preMax = bucketMax[i];
}
maxGap = Math.max(max - preMax, maxGap);
return maxGap;
}
}