题目链接:https://leetcode.com/problems/maximum-gap/
题意:给定一个无序数组,求有序情况下相邻元素差最大为多少?
要求:时间复杂度和空间复杂度均为O(n)
法一:我们很容易能够想到基数排序,它的时间复杂度和空间复杂度都是O(n),排好序之后扫一遍就行了。这样当然是没有问题的。代码如下:
class Solution {
public:
void radixSort(vector<int>& nums)
{
int b = sizeof(int);
int n = nums.size();
vector<int> tmp(n,0);
for(int t=0; t<b; ++t){
vector<int> c(256,0);
for(int i=0; i<n; ++i){
int p = 255&(nums[i]>>(t*8));
++ c[p];
}
c[255] = n - c[255];
for(int i=254; i>=0; --i){
c[i] = c[i+1] - c[i];
}
for(int i=0; i<n; ++i){
int p = 255&(nums[i]>>(t*8));
tmp[c[p]++] = nums[i];
}
nums = tmp;
}
int k = n;
for(int i=n-1; i>=0; --i){
if(nums[i] > 0){
k = i+1;
break;
}
}
int t = 0;
for(int i=k; i<n; ++i){
nums[t++] = tmp[i];
}
for(int i=0; i<k; ++i){
nums[t++] = tmp[i];
}
}
int maximumGap(vector<int>& nums) {
int n = nums.size();
if(n < 2) return 0;
int ret = 0;
radixSort(nums);
for(int i=1; i<n; ++i){
ret = max(ret, nums[i]-nums[i-1]);
}
return ret;
}
};
法二:有没有一种不需要排序的方法呢?我们可以借鉴前面的基数排序的思想,考虑桶排序:假设数组中最大元素是maxx,最小元素是minx,则平均间隔为avg = floor((maxx-minx)/n);那么max gap一定大于等于avg。利用avg可以将数组分成(maxx-minx)/avg+1个桶。那么max gap应该在相邻两个不为空的桶max(min(p2) - max(p1) )中。整体的话就是分为两步:分桶;统计。代码如下:
class Solution {
public:
int maximumGap(vector<int>& nums){
int n = nums.size();
if(n < 2) return 0;
int ret = 0;
int minx = nums[0], maxx = nums[0];
for(int i=1; i<n; ++i){
if(nums[i] > maxx) maxx = nums[i];
if(nums[i] < minx) minx = nums[i];
}
if(maxx == minx) return 0;
int avg = (maxx-minx)/n; // max gap必然 >= avg
if(avg == 0) ++ avg;
ret = avg;
int m = (maxx - minx)/avg + 1;
vector<int> h1(m,INT_MIN), h0(m,INT_MAX); // 保存每个桶中的最大值和最小值
for(int i=0; i<n; ++i){
int p = (nums[i] - minx)/avg;
if(nums[i] > h1[p]){
h1[p] = nums[i];
}
if(nums[i] < h0[p]){
h0[p] = nums[i];
}
}
int pre = 0;
for(int i=1; i<m; ++i){
if(h0[i] < INT_MAX){
if(h0[i] - h1[pre] > ret){
ret = h0[i] - h1[pre];
}
pre = i;
}
}
return ret;
}
};