Smallest Range Covering Elements from K Lists

HardK-way Merge · Min-Heap · Sliding Window🧩 K-Way MergeLeetCode #632 ↗Updated

Problem

You have k lists of integers, each sorted in non-decreasing order. Find the smallest range [a, b] that contains at least one number from every list. A range is smaller if b - a is smaller, or, for equal widths, if a is smaller. Return it as [a, b].
Inputnums = [[4,10,15,24,26],[0,9,12,20],[5,18,22,30]]Output[20,24]
Inputnums = [[1,2,3],[1,2,3],[1,2,3]]Output[1,1]
Inputnums = [[1,10],[2,11]]Output[1,2] (ties with [10,11], smaller start wins)

1 ≤ k ≤ 3500  ·  1 ≤ list length ≤ 50  ·  -105 ≤ values ≤ 105

Try it yourself

Java
class Solution {
    public int[] smallestRange(List<List<Integer>> nums) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Hold one pointer per list. The current picks form a valid range [min, max]; the only move that can shrink it is to advance the list holding the minimum. A min-heap finds that list in O(log k) while a running max tracks the top.
PatternK-Way Merge

Instinct Several sorted lists, rows or streams and you need the global order, the k-th smallest or a range: keep one cursor per list in a min-heap.

Memory hack Line up the heads, crown the smallest, then let its next-in-line step up.

Open the K-Way Merge guide →

Approaches

Brute ForceTry Every Value as the Left End

Time O(N2)Space O(1)

The best range starts at some list element a. For a fixed a, the tightest right end is the max over lists of each list's smallest element ≥ a (found by scanning). Skip a if some list has nothing ≥ it. N is the total number of elements.

Java
public int[] smallestRange(List<List<Integer>> nums) {
    int[] best = null;
    for (List<Integer> source : nums) {
        for (int a : source) {
            int b = a;
            boolean ok = true;
            for (List<Integer> list : nums) {
                Integer ceil = null; // smallest element >= a in this list
                for (int v : list) {
                    if (v >= a) { ceil = v; break; }
                }
                if (ceil == null) { ok = false; break; }
                b = Math.max(b, ceil);
            }
            if (ok && (best == null || b - a < best[1] - best[0]
                    || (b - a == best[1] - best[0] && a < best[0]))) {
                best = new int[]{a, b};
            }
        }
    }
    return best;
}

Direct and obviously correct, but each candidate rescans all N elements.

At a glance

LevelApproachTimeSpace
Brute ForceTry Every Value as the Left EndO(N2)O(1)
BetterMerge Everything, then Sliding WindowO(N log N)O(N)
OptimalK-way Merge: Min-Heap of List Heads + Running MaxO(N log k)O(k)
Common pitfalls
  • Advancing the list with the max instead of the min — the range only grows.
  • Using <= when updating: an equal-width range found later has a larger start.
  • Continuing after a list is exhausted — any further range would miss that list.
Interview tips
  • Frame it as “pick one element per list, minimise max − min”.
  • Justify the greedy: advancing the min is the only move that can improve the range.
  • Mention the sorted-merge + sliding-window version as an alternative mental model.
Pattern
K-way merge with a running max → choose one element from each sorted list to optimise a spread.
My notes saved in this browser