The problem. Given an integer array nums, return the maximum difference between two successive elements in its sorted form. Return 0 if there are fewer than two elements. You must solve it in linear time and linear space.
nums = [3, 6, 9, 1] -> 3 (sorted 1, 3, 6, 9: every gap is 3)
nums = [1, 10, 5, 50, 52, 25] -> 25 (sorted 1, 5, 10, 25, 50, 52)
nums = [10] -> 0Sorting and scanning neighbours is O(n log n) — too slow for the requirement. But we don't need the full order, only the largest gap. With n values between lo and hi, there are n − 1 gaps adding up to hi − lo, so the largest is at least the average, (hi − lo) / (n − 1).
So cut the range into buckets narrower than that. Two values in the same bucket are closer than the average gap, so the maximum gap never lies inside a bucket — it always runs from the largest value of one non-empty bucket to the smallest value of the next non-empty one. Each bucket only needs its min and max, and one scan over the buckets finds the answer: linear time, no sorting.
function maximumGap(nums) { const a = [...nums].sort((x, y) => x - y); let best = 0; for (let i = 1; i < a.length; i++) best = Math.max(best, a[i] - a[i - 1]); return best;}Time O(n log n), space O(n). Correct, but it breaks the linear-time requirement. (Radix sort would make this approach linear for 32-bit integers too.)
Drop each value into a bucket narrower than the average gap, then compare neighbouring non-empty buckets.
function maximumGap(nums) { const n = nums.length; if (n < 2) return 0; const lo = Math.min(...nums), hi = Math.max(...nums); if (lo === hi) return 0; const size = Math.max(1, Math.floor((hi - lo) / (n - 1))); // the biggest gap is at least this wide const count = Math.floor((hi - lo) / size) + 1; const bucketMin = new Array(count).fill(Infinity); const bucketMax = new Array(count).fill(-Infinity); for (const x of nums) { const b = Math.floor((x - lo) / size); bucketMin[b] = Math.min(bucketMin[b], x); bucketMax[b] = Math.max(bucketMax[b], x); } let best = 0, prevMax = lo; for (let b = 0; b < count; b++) { if (bucketMin[b] === Infinity) continue; // empty bucket best = Math.max(best, bucketMin[b] - prevMax); // gaps inside a bucket are never the biggest prevMax = bucketMax[b]; } return best;}Time O(n), space O(n). There are about n buckets; filling them and scanning them are both linear. Why bucket width ⌊(hi − lo)/(n − 1)⌋ is safe: two values in one bucket differ by at most width − 1, which is less than the average gap and so less than the maximum gap.
This is the hardest question in the chapter because the trick is a counting argument, not code: once you see that the maximum gap is at least the average gap, the buckets follow.
hi - lo in a 64-bit type.