(LeetCode) -164 最大间距
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。
如果数组元素个数小于 2,则返回 0。
示例 1:
输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
示例 2:
输入: [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。
说明:
你可以假设数组中所有元素都是非负整数,且数值在 32 位有符号整数范围内。
请尝试在线性时间复杂度和空间复杂度的条件下解决此问题。
解题思路
第一时间想到的也是最简单的,先将所给数组排序,再遍历一遍数组找出最大间距
复杂度分析
-
时间复杂度:O(nlogn)。排序的复杂度是 O(nlogn),遍历的复杂度是O(n),总复杂度是O(nlogn)。
-
空间复杂度:除去输入数组之外,不需要额外空间(因为大多数都是原地排序)
但是题目既然让我们尝试在线性时间复杂度的条件下解决问题,我们就来试一试。
在这里我们使用桶排序
桶排序
首先我们来了解一下桶排序的思想。桶排序是体现了分治的思想。原理是创建若干个桶,通过某种映射将待排序的元素放置到桶中,使每个桶中的最大值都小于他后面一个桶的最小值,并且每个桶容纳的元素数量尽可能平均。然后对每个桶中的元素排序。最后将所有桶中的元素依次输出。
题目要求在线性时间复杂度和空间复杂度的前提下找到相邻元素的最大差。
我们可以先对元素进行排序,为了达到线性时间复杂度,我们采用桶排序(也可以使用计数排序,不过使用桶排序在该题中空间复杂度更小)。
我们可以很巧妙地设置每个桶的大小:假设所有元素的最大值为max,最小值为min,元素个数是n,则最大间距将不小于(max-min)/(n-1)。因此,我们设置桶的容量是(max-min)/(n-1),则桶内的元素的间距肯定不是最大间距,我们只需要查看桶间的间距(前一个桶的最大值和后一个桶的最小值的差)的最大值即可。
此外,在桶内并不需要保存每个元素,只需要保存该桶的最大值和最小值即可。
代码实现(Java)
class Solution {
public int maximumGap(int[] nums) {
if (nums.length <= 1) {
return 0;
}
int n = nums.length;
int min = nums[0];
int max = nums[0];
for (int i = 1; i < n; i++) {
min = Math.min(nums[i], min);
max = Math.max(nums[i], max);
}
if(max - min == 0) {
return 0;
}
int interval = (int) Math.ceil((double)(max - min) / (n - 1));
int[] bucketMin = new int[n - 1];
int[] bucketMax = new int[n - 1];
Arrays.fill(bucketMin, Integer.MAX_VALUE);
Arrays.fill(bucketMax, -1);
for (int i = 0; i < nums.length; i++) {
int index = (nums[i] - min) / interval;
if(nums[i] == min || nums[i] == max) {
continue;
}
bucketMin[index] = Math.min(nums[i], bucketMin[index]);
bucketMax[index] = Math.max(nums[i], bucketMax[index]);
}
int maxGap = 0;
int previousMax = min;
for (int i = 0; i < n - 1; i++) {
if (bucketMax[i] == -1) {
continue;
}
maxGap = Math.max(bucketMin[i] - previousMax, maxGap);
previousMax = bucketMax[i];
}
maxGap = Math.max(max - previousMax, maxGap);
return maxGap;
}
}