🧠
Heap-based Approach (K-way Merge of Sorted Pairs)
💡 This approach uses a min-heap to generate pairs in ascending order of distance without enumerating all pairs, useful for understanding priority queues and lazy evaluation.
Intuition
Sort the array, then use a min-heap to push pairs starting with the smallest distances. Extract the smallest pair distance k times to find the k-th smallest.
Algorithm
- Sort the array nums.
- Initialize a min-heap and push pairs (nums[i], nums[i+1]) with their distances.
- Pop the smallest distance pair from the heap k-1 times.
- Each time you pop a pair (i, j), if j+1 < n, push the pair (i, j+1) into the heap.
- After k-1 pops, the top of the heap is the k-th smallest pair distance.
💡 This simulates merging sorted lists of pair distances starting from each element, but can be slower due to heap operations.
import heapq
def smallestDistancePair(nums, k):
nums.sort()
n = len(nums)
min_heap = []
for i in range(n - 1):
heapq.heappush(min_heap, (nums[i+1] - nums[i], i, i+1))
for _ in range(k - 1):
dist, i, j = heapq.heappop(min_heap)
if j + 1 < n:
heapq.heappush(min_heap, (nums[j+1] - nums[i], i, j + 1))
return min_heap[0][0]
# Driver code
if __name__ == '__main__':
print(smallestDistancePair([1,3,1], 1)) # Output: 0
Line Notes
nums.sort()Sort array to generate pairs in order
for i in range(n - 1)Initialize heap with pairs of adjacent elements
heapq.heappush(min_heap, (nums[i+1] - nums[i], i, i+1))Push initial pairs with their distances
dist, i, j = heapq.heappop(min_heap)Pop smallest distance pair
if j + 1 < nIf next pair exists for i, push it to heap
heapq.heappush(min_heap, (nums[j+1] - nums[i], i, j + 1))Push next pair from i to heap
return min_heap[0][0]Return k-th smallest pair distance
import java.util.*;
public class Solution {
public int smallestDistancePair(int[] nums, int k) {
Arrays.sort(nums);
int n = nums.length;
PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
for (int i = 0; i < n - 1; i++) {
minHeap.offer(new int[]{nums[i+1] - nums[i], i, i+1});
}
for (int count = 0; count < k - 1; count++) {
int[] curr = minHeap.poll();
int dist = curr[0], i = curr[1], j = curr[2];
if (j + 1 < n) {
minHeap.offer(new int[]{nums[j+1] - nums[i], i, j+1});
}
}
return minHeap.peek()[0];
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.smallestDistancePair(new int[]{1,3,1}, 1)); // Output: 0
}
}
Line Notes
Arrays.sort(nums)Sort array for ordered pair generation
PriorityQueue<int[]> minHeapMin-heap to store pairs by distance
minHeap.offer(new int[]{nums[i+1] - nums[i], i, i+1})Push initial adjacent pairs
int[] curr = minHeap.poll()Pop smallest distance pair
if (j + 1 < n)Check if next pair from i exists
minHeap.offer(new int[]{nums[j+1] - nums[i], i, j+1})Push next pair from i
return minHeap.peek()[0]Return k-th smallest pair distance
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int smallestDistancePair(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int n = nums.size();
auto cmp = [](const tuple<int,int,int>& a, const tuple<int,int,int>& b) {
return get<0>(a) > get<0>(b);
};
priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, decltype(cmp)> minHeap(cmp);
for (int i = 0; i < n - 1; i++) {
minHeap.emplace(nums[i+1] - nums[i], i, i+1);
}
for (int count = 0; count < k - 1; count++) {
auto [dist, i, j] = minHeap.top();
minHeap.pop();
if (j + 1 < n) {
minHeap.emplace(nums[j+1] - nums[i], i, j+1);
}
}
return get<0>(minHeap.top());
}
int main() {
vector<int> nums = {1,3,1};
cout << smallestDistancePair(nums, 1) << endl; // Output: 0
return 0;
}
Line Notes
sort(nums.begin(), nums.end())Sort array for ordered pair generation
priority_queue<tuple<int,int,int>> minHeapMin-heap to store pairs by distance
minHeap.emplace(nums[i+1] - nums[i], i, i+1)Push initial adjacent pairs
auto [dist, i, j] = minHeap.top()Get smallest distance pair
minHeap.pop()Remove smallest pair from heap
if (j + 1 < n)Check if next pair from i exists
minHeap.emplace(nums[j+1] - nums[i], i, j+1)Push next pair from i
return get<0>(minHeap.top())Return k-th smallest pair distance
class MinHeap {
constructor() {
this.heap = [];
}
swap(i, j) {
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
}
push(val) {
this.heap.push(val);
this.bubbleUp();
}
bubbleUp() {
let idx = this.heap.length - 1;
while (idx > 0) {
let parent = Math.floor((idx - 1) / 2);
if (this.heap[parent][0] <= this.heap[idx][0]) break;
this.swap(parent, idx);
idx = parent;
}
}
pop() {
if (this.heap.length === 1) return this.heap.pop();
const top = this.heap[0];
this.heap[0] = this.heap.pop();
this.bubbleDown();
return top;
}
bubbleDown() {
let idx = 0;
const length = this.heap.length;
while (true) {
let left = 2 * idx + 1;
let right = 2 * idx + 2;
let smallest = idx;
if (left < length && this.heap[left][0] < this.heap[smallest][0]) smallest = left;
if (right < length && this.heap[right][0] < this.heap[smallest][0]) smallest = right;
if (smallest === idx) break;
this.swap(idx, smallest);
idx = smallest;
}
}
peek() {
return this.heap[0];
}
}
function smallestDistancePair(nums, k) {
nums.sort((a, b) => a - b);
const n = nums.length;
const minHeap = new MinHeap();
for (let i = 0; i < n - 1; i++) {
minHeap.push([nums[i+1] - nums[i], i, i+1]);
}
for (let count = 0; count < k - 1; count++) {
const [dist, i, j] = minHeap.pop();
if (j + 1 < n) {
minHeap.push([nums[j+1] - nums[i], i, j + 1]);
}
}
return minHeap.peek()[0];
}
// Test
console.log(smallestDistancePair([1,3,1], 1)); // Output: 0
Line Notes
nums.sort((a, b) => a - b)Sort array for ordered pair generation
const minHeap = new MinHeap()Initialize min-heap for pairs
minHeap.push([nums[i+1] - nums[i], i, i+1])Push initial adjacent pairs
const [dist, i, j] = minHeap.pop()Pop smallest distance pair
if (j + 1 < n)Check if next pair from i exists
minHeap.push([nums[j+1] - nums[i], i, j + 1])Push next pair from i
return minHeap.peek()[0]Return k-th smallest pair distance
TimeO(n log n + k log n)
SpaceO(n)
Sorting takes O(n log n). The heap can have up to n elements, and we perform k extractions and insertions each O(log n).
💡 For large k close to n^2, this approach is slower than binary search, but it is useful to understand heap usage.
Interview Verdict: Accepted but less efficient
This approach works but is less optimal for large inputs compared to binary search on answer space.