↓Skip to main content
  1. LeetCode/

LeetCode 632: Smallest Range Covering Elements from K Lists

·3 mins· ·
LeetCode Hard Heap K-Way-Merge Sliding-Window
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-01-18

  • Submissions: Time Limit Exceeded → Wrong Answer → Accepted → Wrong Answer → Accepted (rewritten the same day)

Approach
#

Find the smallest range [a, b] that contains at least one number from every list.

Take one “current element” from each list; the minimum and maximum of those k numbers form a valid range. To shrink it, only advancing the list holding the minimum can help: advancing the list with the maximum only widens the range.

This is the same as a k-way merge:

  1. Put the first element of each list in a heap and track the current maximum.
  2. Pop the minimum and update the answer with [minimum, maximum].
  3. Push the next element of that list and update the maximum.
  4. Stop when a list runs out: no later range can include that list.

My Attempts
#

TLE: push everything and recompute min and max each time
#

All elements went into the heap; while popping, a dict kept the last value seen per list, and once all k lists were present, every step took min and max over the dict. Each step is O(k), O(N k) in total.

Wrong Answer: starting the maximum at 0
#

current_max = 0

Values can be negative. If every value is negative, the maximum stays 0 and the range is wrong. Start at float("-inf").

Something odd
#

The first accepted version returned [min_end, min_start], where min_end held the maximum and min_start the minimum. The order looks reversed, yet it was judged Accepted. The rewrite the same day returned [best_min, best_max]. I use the correct order going forward.

Solution
#

import heapq

class Solution:
    def smallestRange(self, nums: List[List[int]]) -> List[int]:
        heap = [(lst[0], i, 0) for i, lst in enumerate(nums)]
        heapq.heapify(heap)
        current_max = max(lst[0] for lst in nums)
        best_min, best_max = float("-inf"), float("inf")

        while True:
            current_min, i, j = heapq.heappop(heap)
            if current_max - current_min < best_max - best_min:
                best_min, best_max = current_min, current_max

            if j + 1 == len(nums[i]):
                break                                   # this list is used up
            nxt = nums[i][j + 1]
            heapq.heappush(heap, (nxt, i, j + 1))
            current_max = max(current_max, nxt)

        return [best_min, best_max]

Updating with < works because minimums are popped in increasing order: among equal widths, the first range found has the smaller start, which matches the tie rule.

Complexity
#

Time O(N log k), where N is the total number of elements. Space O(k).

Mistakes to Avoid
#

  • Starting the maximum at 0.
  • Advancing the list with the maximum: only advancing the minimum can shrink the range.
  • Continuing after a list runs out: no later range can include it.

Interview Explanation
#

Taking one current element per list, their minimum and maximum form a valid range, and only advancing the list with the minimum can make it smaller. So I keep each list’s current element in a heap along with the running maximum: pop the minimum, update the answer, push the next element of the same list, and stop when a list is exhausted. Time O(N log k).

Related

LeetCode 2009: Minimum Number of Operations to Make Array Continuous
·2 mins
LeetCode Hard Sliding-Window Hash-Table Binary-Search Array
LeetCode 2009 note: the result is n consecutive integers; after deduplicating and sorting, a sliding window finds the most distinct values within a span of n - 1, and the rest must change
LeetCode 2781: Length of the Longest Valid Substring
·3 mins
LeetCode Hard Sliding-Window Hash-Table String Trie
LeetCode 2781 note: forbidden words are at most 10 long, so each right end checks only the last 10 suffixes; on a match push the left end past it, using the shortest match (the rightmost start)
LeetCode 2106: Maximum Fruits Harvested After at Most K Steps
·2 mins
LeetCode Hard Sliding-Window Prefix-Sum Binary-Search Array
LeetCode 2106 note: the harvest is always a contiguous block of fruits; covering [L, R] takes (R - L) + min(|start - L|, |R - start|) steps, so slide a window over the fruits array
LeetCode 220: Contains Duplicate III
·3 mins
LeetCode Hard Sliding-Window Bucket-Sort Ordered-Set Sorting Array
LeetCode 220 note: with bucket size valueDiff + 1, two numbers in one bucket always qualify, so only the two neighboring buckets need checking; the window keeps the latest indexDiff numbers, so each bucket holds at most one
LeetCode 2156: Find Substring With Given Hash Value
·3 mins
LeetCode Hard Sliding-Window Rolling-Hash String
LeetCode 2156 note: the first character has weight p^0, so sliding right to left needs only multiply by p, add the new character, and subtract the outgoing one times p^k; the modulus may not be prime, so no modular inverse
LeetCode 2953: Count Complete Substrings
·3 mins
LeetCode Hard Sliding-Window Hash-Table String
LeetCode 2953 note: split where neighboring letters differ by more than 2; in each segment enumerate the number of distinct letters d, slide a fixed window of d × k, and track how many letters appear exactly k times