给定一个未经排序的数组,请找出其排序表中连续两个要素的最大间距。
如果数组中的要素少于 2 个,请返回 0。
注意事项
可以假定数组中的所有要素都是非负整数,且最大不超过 32 位整数。
样例
给定数组 [1, 9, 2, 5]
,其排序表为 [1, 2, 5, 9]
,其最大的间距是在 5
和 9
之间,= 4
.
挑战
用排序的方法解决这个问题是比较简单的方法,但是排序的时间复杂度是O(nlogn), 能否使用线性的时间和空间复杂度的方法解决这个问题。
思路:
先要给数组排序,要求是线性的时间和空间复杂度,只能用桶排序或者基数排序。用桶排序,首先找出数组的最大值和最小值,然后要确定每个桶的容量,再确定桶的个数,然后需要在每个桶中找出局部最大值和最小值,而最大间距的两个数不会在同一个桶中,而是一个桶的最小值和另一个桶的最大值之间的间距。
class Gap {
public:
int maxGap(vector<int> A, int n) {
int minValue=INT_MAX,maxValue=INT_MIN;
for(int i=0;i<n;i++){
maxValue = max(maxValue, A[i]);
minValue = min(minValue, A[i]);
}
vector<int> bocketMax(n,INT_MIN);
vector<int> bocketMin(n,INT_MAX);
int len=maxValue-minValue;
//桶内不排序,只保留两个数,一个最大值,一个最小值,这两个数不断更新。其他数一概不要。
for(int i=0;i<n;i++){
//桶的宽度d = len/ n,桶的个数为(A[i]- min)/d 桶号:((A[i] - min) * n) / len
int index=(double)(A[i]-minValue)/len*(n-1);//桶号
bocketMax[index]=max(A[i],bocketMax[index]);
bocketMin[index]=min(A[i],bocketMin[index]);
}
//最大间距的两个数不在同一个桶中,而是后一个桶的最小值减去前一个桶的最大值
int res=0,pre=bocketMax[0];
for(int i=1;i<n;i++){
if(bocketMin[i]!=INT_MAX){
res=max(res,bocketMin[i]-pre);
pre=bocketMax[i];//桶号
}
}
return res;
}
};
上面那种AC不能通过,在网上看到下面这个可以:
class Solution {
public:
/*
* @param nums: an array of integers
* @return: the maximun difference
*/
int maximumGap(vector<int> nums) {
if (nums.empty()) return 0;
int mx = INT_MIN, mn = INT_MAX, n = nums.size();
for (int i=0;i<n;i++) {
mx = max(mx, nums[i]);
mn = min(mn, nums[i]);
}
int size = (mx - mn) / n + 1;
int bucket_nums = (mx - mn) / size + 1;
vector<int> bucket_min(bucket_nums, INT_MAX);
vector<int> bucket_max(bucket_nums, INT_MIN);
set<int> s;
for (int i=0;i<n;i++) {
int idx = (nums[i] - mn) / size;
bucket_min[idx] = min(bucket_min[idx], nums[i]);
bucket_max[idx] = max(bucket_max[idx], nums[i]);
s.insert(idx);//在set中插入元素
}
int pre = 0, res = 0;
for (int i = 1; i < n; ++i) {
if (!s.count(i)) continue;//查找键key的元素个数
res = max(res, bucket_min[i] - bucket_max[pre]);
pre = i;
}
return res;
}
};