桶排序(划分区间)
一次遍历找到区间内最大值
M
a
x
Max
Max ,最小值
M
i
n
Min
Min 。区间
(
M
i
n
,
M
a
x
]
(Min,Max]
(Min,Max] 左开右闭,划分为
n
−
1
n-1
n−1 个长度为
l
e
n
len
len 的区间 ,划分的区间左开右闭,所以每个子区间有
l
e
n
−
1
len-1
len−1 个数。
根据实际意义,
(
n
−
1
)
(
l
e
n
−
1
)
≤
M
a
x
−
M
i
n
−
1
(n-1)(len-1)\le Max - Min -1
(n−1)(len−1)≤Max−Min−1 时,答案一定不在某个子区间内部取到。
整理上式,得,
l
e
n
≤
⌊
M
a
x
−
M
i
n
+
n
−
2
n
−
1
⌋
=
⌈
M
a
x
−
M
i
n
n
−
1
⌉
len\le\lfloor\frac{Max-Min+n-2}{n-1}\rfloor=\lceil\frac{Max-Min}{n-1}\rceil
len≤⌊n−1Max−Min+n−2⌋=⌈n−1Max−Min⌉ ,
C
+
+
C++
C++ 代码只使用不等式的前半段。
有了子区间的长度,数字就可以对应到子区间了。再次遍历 n u m s nums nums ,维护每个子区间的最大值 m a x max max ,最小值 m i n min min ,区间是否用到 u s e d used used 。
最后遍历所有子区间,维护答案,即为所求。
class Solution {
public:
int maximumGap(vector<int>& nums) {
const int INF = 0x3f3f3f3f;
struct Range{
int min,max;
bool used;
Range () : min(INF) , max ( -INF) , used(false) {}
};
int n = nums.size();
int Min = INF, Max = -INF;
for(auto &x:nums){
Min = Min<x?Min:x;
Max = Max>x?Max:x;
}
if(nums.size()<2||Min==Max) return 0;
vector<Range> r(n-1);
int len = (Max - Min + n - 2) /(n-1);
for(auto &x:nums){
if( x == Min) continue;
int i = (x - Min -1) / len;
r[i].min = min(r[i].min,x);
r[i].max = max(r[i].max,x);
r[i].used = true;
}
int ans = 0 ;
for(int i = 0,last = Min;i<n-1;i++){
if(!r[i].used) continue;
ans = max(ans,r[i].min - last);
last = r[i].max;
}
return ans;
}
};
- 时间复杂度 : O ( n ) O(n) O(n) , n n n 是数字数量, 找出最大最小值,计算每个桶的最大最小值,遍历所有桶维护答案,总时间复杂度 O ( 3 × n ) O(3\times n) O(3×n) ,忽略常数时间复杂度 O ( n ) O(n) O(n) 。
- 空间复杂度 : O ( n ) O(n) O(n) , n − 1 n-1 n−1 个桶的空间复杂度 O ( n ) O(n) O(n) 。
AC
致语
- 理解思路很重要!
- 欢迎读者在评论区留言,墨染看到就会回复的。