桶排序
class Solution {
public:
class Bucket{
public:
bool used = false;
int maxval = INT_MIN;
int minval = INT_MAX;
};
int mins = INT_MAX, maxn = INT_MIN;
int maximumGap(vector<int>& nums) {
int n = nums.size();
if (n < 2) return 0;
for (int& x:nums)
{
maxn = max(maxn, x);
mins = min(mins, x);
}
// 分配桶的长度和个数是桶排序的关键
// 在 n 个数下,形成的两两相邻区间是 n - 1 个,比如 [2,4,6,8] 这里
// 有 4 个数,但是只有 3 个区间,[2,4], [4,6], [6,8]
// 因此,桶长度 = 区间总长度 / 区间总个数 = (max - min) / (nums.length - 1)
int bucketSize = max(1, (maxn-mins)/(n-1));
// 上面得到了桶的长度,我们就可以以此来确定桶的个数
// 桶个数 = 区间长度 / 桶长度
// 这里考虑到实现的方便,多加了一个桶,为什么?
// 还是举上面的例子,[2,4,6,8], 桶的长度 = (8 - 2) / (4 - 1) = 2
// 桶的个数 = (8 - 2) / 2 = 3
// 已知一个元素,需要定位到桶的时候,一般是 (当前元素 - 最小值) / 桶长度
// 这里其实利用了整数除不尽向下取整的性质
// 但是上面的例子,如果当前元素是 8 的话 (8 - 2) / 2 = 3,对应到 3 号桶
// 如果当前元素是 2 的话 (2 - 2) / 2 = 0,对应到 0 号桶
// 你会发现我们有 0,1,2,3 号桶,实际用到的桶是 4 个,而不是 3 个
// 透过例子应该很好理解,但是如果要说根本原因,其实是开闭区间的问题
// 这里其实 0,1,2 号桶对应的区间是 [2,4),[4,6),[6,8)
// 那 8 怎么办?多加一个桶呗,3 号桶对应区间 [8,10)
int bucketNum = (maxn-mins)/bucketSize+1;
vector<Bucket> bucket(bucketNum);
for (int& x:nums)
{
int bucketIdx = (x-mins)/bucketSize;
bucket[bucketIdx].used = true;
bucket[bucketIdx].maxval = max(x, bucket[bucketIdx].maxval);
bucket[bucketIdx].minval = min(x, bucket[bucketIdx].minval);
}
int prevBucketMax = mins, maxGap = 0;
for (auto& bk:bucket)
{
if (!bk.used) continue;
maxGap = max(maxGap, bk.minval-prevBucketMax);
prevBucketMax = bk.maxval;
}
return maxGap;
}
};