LeetCode 164中等排序/桶
最大间距 图解题解
这道题到底在问什么
给定无序整数数组 nums,返回它排序后相邻元素之间的最大差值。若元素不足两个,返回 0。
- 输入
- nums=[3,6,9,1]
- 输出
- 3 (排序后 [1,3,6,9],相邻差 2,3,3,最大 3)
- 输入
- nums=[10]
- 输出
- 0 (不足两个元素,没有相邻对)
- 输入
- nums=[1,100]
- 输出
- 99 (只有一个间距)
最优解:一步一步想明白
- 3记住这句:答案藏在「相邻非空桶之间」,桶内差值永远不够大。下面每一帧都在套它。
- 4先定桶:最小 1、最大 9、共 5 个数,算出桶宽 size=2、桶数 5。每个桶只存它见过的最小值和最大值。
- 5看第 0 个数 1(紫色):用 (1-1)/2 算出它该进桶0。
- 61 落进桶0,这桶刚被点亮,min 和 max 都先记成 1。
- 7看第 1 个数 3(紫色):用 (3-1)/2 算出它该进桶1。
- 83 落进桶1,这桶刚被点亮,min 和 max 都先记成 3。
- 9看第 2 个数 6(紫色):用 (6-1)/2 算出它该进桶2。
- 106 落进桶2,这桶刚被点亮,min 和 max 都先记成 6。
- 11看第 3 个数 9(紫色):用 (9-1)/2 算出它该进桶4。
- 129 落进桶4,这桶刚被点亮,min 和 max 都先记成 9。
- 13看第 4 个数 4(紫色):用 (4-1)/2 算出它该进桶1。
- 144 也落进桶1,刷新这桶的 min=3、max=4。同桶内差值最多 1,不可能是答案。
- 15所有数都入桶了。现在从左到右扫每个非空桶,只比「上一非空桶的 max」和「当前桶的 min」这一段距离。prev 起步用最小值 1。
- 16轮到非空桶0(紫框)。跨桶间距 = 本桶最小 1 减去上一非空桶的 max 1,得 0。
- 170 没超过当前最大间距 0,ans 不变。prev 推进到本桶 max 1。
- 18轮到非空桶1(紫框)。跨桶间距 = 本桶最小 3 减去上一非空桶的 max 1,得 2。
- 192 比之前的最大间距大,刷新 ans=2。再把 prev 推到本桶 max 4,准备比下一个非空桶。
- 20轮到非空桶2(紫框)。跨桶间距 = 本桶最小 6 减去上一非空桶的 max 4,得 2。
- 212 没超过当前最大间距 2,ans 不变。prev 推进到本桶 max 6。
- 22桶3 是空的(紫框)。空桶直接跳过,不参与比较,prev 保持 6。空桶的存在正说明这里有一道大缝隙。
- 23轮到非空桶4(紫框)。跨桶间距 = 本桶最小 9 减去上一非空桶的 max 6,得 3。
- 243 比之前的最大间距大,刷新 ans=3。再把 prev 推到本桶 max 9,准备比下一个非空桶。
- 25回头验证:把数排好是 [1, 3, 4, 6, 9],相邻差里最大的正是 3。我们没真排序,只靠扫桶就 O(n) 得到了它。
⚠️ 容易写错的地方
✗ 错:桶宽算成 (hi-lo)/n
✓ 对:用 (hi-lo)/(n-1)
n-1 个间距保证最大间距 ≥ size,把答案逼到桶间
✗ 错:size 取到 0 或漏特判
✓ 对:max(1,…) 兜底,长度不足或 lo==hi 返回 0
整除可能得 0,须夹到至少 1
✗ 错:去比桶内而非桶间
✓ 对:只比上一非空桶 max 到本桶 min
同桶差值 ≤ size-1,永远不够大
完整代码(Python / C++ / Java)
Python
from typing import List
class Solution:
def maximumGap(self, nums: List[int]) -> int:
n = len(nums)
if n < 2:
return 0
lo, hi = min(nums), max(nums)
if lo == hi:
return 0
size = max(1, (hi - lo) // (n - 1))
cnt = (hi - lo) // size + 1
bmin = [10**20] * cnt
bmax = [-(10**20)] * cnt
used = [False] * cnt
for x in nums:
i = (x - lo) // size
bmin[i] = min(bmin[i], x)
bmax[i] = max(bmax[i], x)
used[i] = True
ans, prev = 0, lo
for i in range(cnt):
if not used[i]:
continue
ans = max(ans, bmin[i] - prev)
prev = bmax[i]
return ansC++
#include <algorithm>
#include <climits>
#include <vector>
using namespace std;
class Solution {
public:
int maximumGap(vector<int>& nums) {
int n = nums.size();
if (n < 2) return 0;
int lo = *min_element(nums.begin(), nums.end()), hi = *max_element(nums.begin(), nums.end());
if (lo == hi) return 0;
int size = max(1, (hi - lo) / (n - 1));
int cnt = (hi - lo) / size + 1;
vector<int> bmin(cnt, INT_MAX), bmax(cnt, INT_MIN);
vector<bool> used(cnt);
for (int x : nums) {
int i = (x - lo) / size;
bmin[i] = min(bmin[i], x); bmax[i] = max(bmax[i], x); used[i] = true;
}
int ans = 0, prev = lo;
for (int i = 0; i < cnt; ++i) if (used[i]) {
ans = max(ans, bmin[i] - prev);
prev = bmax[i];
}
return ans;
}
};Java
import java.util.*;
class Solution {
public int maximumGap(int[] nums) {
int n = nums.length;
if (n < 2) return 0;
int lo = nums[0], hi = nums[0];
for (int x : nums) { lo = Math.min(lo, x); hi = Math.max(hi, x); }
if (lo == hi) return 0;
int size = Math.max(1, (hi - lo) / (n - 1));
int cnt = (hi - lo) / size + 1;
int[] bmin = new int[cnt], bmax = new int[cnt];
boolean[] used = new boolean[cnt];
Arrays.fill(bmin, Integer.MAX_VALUE);
Arrays.fill(bmax, Integer.MIN_VALUE);
for (int x : nums) {
int i = (x - lo) / size;
bmin[i] = Math.min(bmin[i], x);
bmax[i] = Math.max(bmax[i], x);
used[i] = true;
}
int ans = 0, prev = lo;
for (int i = 0; i < cnt; i++) if (used[i]) {
ans = Math.max(ans, bmin[i] - prev);
prev = bmax[i];
}
return ans;
}
}复杂度
时间
O(n)
求极值、入桶、扫桶各一遍线性
空间
O(n)
桶数与 n 同量级,每桶存 min/max
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 最大间距 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么不直接基数排序(radix sort)后扫一遍?+
基数排序也能做到 O(n),但要按位多轮分配,常数和实现都更重。桶+鸽巢只需一遍极值、一遍入桶、一遍扫桶,思路更短,也是面试更想听到的「为什么 min/max 就够」的洞察。
值域很大(如 10^9)会不会撑爆桶数组?+
不会。桶数 cnt 与 n 同量级(约 n+1),不随值域大小膨胀,因为桶宽随值域自动变宽。所以空间是 O(n) 而非 O(值域)。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 最大间距 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。