题目地址:
https://leetcode.com/problems/maximum-gap/
给定一个长 n n n数组 A A A,设其按从小到大排好序之后是 B B B,求 max 1 ≤ i < n { B [ i ] − B [ i − 1 ] } \max_{1\le i< n}\{B[i]-B[i-1]\} max1≤i<n{B[i]−B[i−1]}。如果 n < 2 n<2 n<2则返回 0 0 0。题目保证 A [ i ] ≥ 0 A[i]\ge 0 A[i]≥0。
设 A A A的最小值和最大值分别为 m , M m,M m,M,我们尝试将 ( m , M ] (m, M] (m,M]平均划分为若干个左开右闭的区间,然后想象一下将 A A A中的所有数都放进去。设最终答案是 y y y,则有 ( n − 1 ) y ≥ M − m (n-1)y\ge M-m (n−1)y≥M−m,即 y ≥ M − m n − 1 y\ge \frac{M-m}{n-1} y≥n−1M−m,我们令平均划分的区间长度为 x x x,那么该区间中的 A A A的数的差值都是小于等于 x − 1 x-1 x−1的,我们就取 x − 1 < M − m n − 1 x-1<\frac{M-m}{n-1} x−1<n−1M−m,那么得 x − 1 < y x-1<y x−1<y,从而同一个区间内部的两个数的差不可能等于答案,从而 y y y只能是不同区间的数的差,我们只需枚举所有的后面一个区间的最小值减去前一个区间的最大值的差,然后找到最大的差即可。 x − 1 < M − m n − 1 ⇔ ( x − 1 ) ( n − 1 ) ≤ M − m − 1 ⇔ x ≤ ⌊ M − m + n − 2 n − 1 ⌋ x-1<\frac{M-m}{n-1}\Leftrightarrow (x-1)(n-1)\le M-m-1\\ \Leftrightarrow x\le \lfloor\frac{M-m+n-2}{n-1}\rfloor x−1<n−1M−m⇔(x−1)(n−1)≤M−m−1⇔x≤⌊n−1M−m+n−2⌋所以我们只需要令 x = ⌊ M − m + n − 2 n − 1 ⌋ x=\lfloor\frac{M-m+n-2}{n-1}\rfloor x=⌊n−1M−m+n−2⌋即可。我们需要开 ⌈ M − m x ⌉ \lceil\frac{M-m}{x}\rceil ⌈xM−m⌉个区间。每个数 a a a属于的区间下标为 a − m − 1 x \frac{a-m-1}{x} xa−m−1(除了 m m m自己,其不属于任何区间)。我们记录一下每个区间是否有 A A A中的数,同时存一下其最大和最小值,最后遍历一遍即可。代码如下:
class Solution {
public:
struct Range {
int min, max;
bool used;
};
int maximumGap(vector<int>& a) {
int n = a.size();
int m = INT_MAX, M = INT_MIN;
for (int x : a) {
m = min(m, x);
M = max(M, x);
}
if (n < 2 || m == M) return 0;
vector<Range> v((M - m + len - 1) / len, {INT_MAX, INT_MIN, false});
int len = (M - m + n - 2) / (n - 1);
for (int x : a) {
if (x == m) continue;
int k = (x - m - 1) / len;
v[k] = {min(v[k].min, x), max(v[k].max, x), true};
}
int res = 0;
for (int i = 0, prev = m; i < n - 1; i++)
if (v[i].used) {
res = max(res, v[i].min - prev);
prev = v[i].max;
}
return res;
}
};
时空复杂度 O ( n ) O(n) O(n)。