LeetCode 373: Find K Pairs with Smallest Sums Solution in Python – A Step-by-Step Guide

Imagine you’ve got two sorted arrays—like [1, 7, 11] and [2, 4, 6]—and you need to pick out the k pairs with the smallest sums, where each pair combines one number from each array. That’s the challenge of LeetCode 373: Find K Pairs with Smallest Sums, a medium-level problem that blends heap usage with optimization. Using Python, we’ll explore two solutions: the Best Solution—a min-heap approach for O(k log k) efficiency—and an Alternative Solution—brute force at O(mn log (mn)). With examples, clear code breakdowns, and a friendly vibe, this guide will help you find those smallest sums. Let’s pair up!

What Is LeetCode 373: Find K Pairs with Smallest Sums?

Section link icon

LeetCode 373: Find K Pairs with Smallest Sums provides two sorted integer arrays, nums1 and nums2, and an integer k. Your task is to return the k pairs (u, v) where u is from nums1 and v is from nums2, such that their sums (u + v) are the k smallest possible. It’s a problem that tests your ability to efficiently select from a large set of possibilities!

Problem Statement

  • Input:
    • nums1: Sorted list of integers (ascending).
    • nums2: Sorted list of integers (ascending).
    • k: Integer representing the number of pairs to return.
  • Output: List[List[int]] - k pairs with the smallest sums.
  • Rules:
    • Each pair (u, v) has u from nums1, v from nums2.
    • Return pairs in any order, as long as they’re the k smallest sums.

Constraints

  • 1 <= nums1.length, nums2.length <= 10⁵
  • -10⁹ <= nums1[i], nums2[i] <= 10⁹
  • 1 <= k <= min(1000, nums1.length * nums2.length)
  • nums1 and nums2 are sorted in ascending order.

Examples

  • Input: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
    • Output: [[1,2],[1,4],[1,6]]
      • Possible sums: 3(1+2), 5(1+4), 7(1+6), 9(7+2), 11(7+4), 13(7+6), 13(11+2), 15(11+4), 17(11+6).
      • Smallest 3: 3, 5, 7 → [[1,2], [1,4], [1,6]].
  • Input: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
    • Output: [[1,1],[1,1]]
      • Sums: 2(1+1), 2(1+1), 3(1+2), 3(1+2), 3(2+1), 4(2+2), 5(2+3).
      • Smallest 2: 2, 2 → [[1,1], [1,1]].
  • Input: nums1 = [1,2], nums2 = [3], k = 3
    • Output: [[1,3],[2,3]]
      • Sums: 4(1+3), 5(2+3), only 2 pairs possible.

These show the pairing puzzle—let’s solve it!

Understanding the Problem: Finding K Smallest Pairs

Section link icon

To tackle LeetCode 373 in Python, we need to: 1. Generate pairs (u, v) from nums1 and nums2. 2. Compute their sums (u + v). 3. Select the k pairs with the smallest sums.

A naive approach might compute all sums and sort, but that’s inefficient. Instead, we’ll use:

  • Best Solution: Min-heap—O(k log k) time, O(k) space—fast and optimized.
  • Alternative Solution: Brute force—O(m*n log (m*n)) time, O(m*n) space—simple but slow.

Let’s optimize with the best solution!

Best Solution: Min-Heap

Section link icon

Why This Is the Best Solution

The min-heap approach runs in O(k log k) time by maintaining a priority queue of pairs, starting with the smallest possible sum and expanding only as needed. It leverages the sorted nature of the input arrays to avoid generating all m*n pairs—making it the most efficient solution for this problem!

How It Works

Think of it like a priority line:

  • Heap: Use a min-heap with (sum, i, j) where sum = nums1[i] + nums2[j], i and j are indices.
  • Start: Push (nums1[0] + nums2[0], 0, 0).
  • Expand: Pop smallest sum, add pair, push next pairs (i+1, j) and (i, j+1) if valid, track seen pairs.
  • Repeat: k times to get k smallest sums.
  • Result: List of k pairs.

It’s like picking the next smallest pair smartly!

Step-by-Step Example

For nums1 = [1,7,11], nums2 = [2,4,6], k = 3:

  • Init: Heap = [(3, 0, 0)] (1+2), Seen = {(0,0)}, Result = [].
  • Step 1:
    • Pop (3, 0, 0), Result = [[1,2]].
    • Push (5, 0, 1) (1+4), (9, 1, 0) (7+2).
    • Heap = [(5, 0, 1), (9, 1, 0)], Seen = {(0,0), (0,1), (1,0)}.
  • Step 2:
    • Pop (5, 0, 1), Result = [[1,2], [1,4]].
    • Push (7, 0, 2) (1+6), (11, 1, 1) (7+4).
    • Heap = [(7, 0, 2), (9, 1, 0), (11, 1, 1)].
  • Step 3:
    • Pop (7, 0, 2), Result = [[1,2], [1,4], [1,6]].
    • Push (13, 1, 2) (7+6), (0,2 not added, out of bounds).
    • Heap = [(9, 1, 0), (11, 1, 1), (13, 1, 2)].
  • Result: [[1,2], [1,4], [1,6]] (sums 3, 5, 7).

For nums1 = [1,1,2], nums2 = [1,2,3], k = 2:

  • Init: Heap = [(2, 0, 0)], Result = [].
  • Step 1: Pop (2, 0, 0), Result = [[1,1]], Heap = [(2, 0, 1), (3, 1, 0)].
  • Step 2: Pop (2, 0, 1), Result = [[1,1], [1,2]], Heap = [(3, 0, 2), (3, 1, 0)].
  • Result: [[1,1], [1,2]] (both sum to 2).

Code with Explanation

Here’s the Python code using a min-heap:

from heapq import heappush, heappop

class Solution:
    def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:
        if not nums1 or not nums2:
            return []

        # Min-heap: (sum, i, j) where i is index in nums1, j in nums2
        heap = []
        seen = set()
        result = []

        # Start with smallest pair
        heappush(heap, (nums1[0] + nums2[0], 0, 0))
        seen.add((0, 0))

        # Get k smallest pairs
        while heap and len(result) < k:
            curr_sum, i, j = heappop(heap)
            result.append([nums1[i], nums2[j]])

            # Add next possible pairs
            if i + 1 < len(nums1) and (i + 1, j) not in seen:
                heappush(heap, (nums1[i + 1] + nums2[j], i + 1, j))
                seen.add((i + 1, j))
            if j + 1 < len(nums2) and (i, j + 1) not in seen:
                heappush(heap, (nums1[i] + nums2[j + 1], i, j + 1))
                seen.add((i, j + 1))

        return result

Explanation

  • Lines 5-7: Handle empty input cases.
  • Lines 9-10: heap: Min-heap of (sum, i, j), seen: Track visited pairs.
  • Lines 13-14: Push initial pair (nums1[0] + nums2[0], 0, 0).
  • Lines 16-25: Main loop:
    • Pop smallest sum, add pair to result.
    • Push (i+1, j) and (i, j+1) if valid and unseen.
    • Repeat k times or until heap is empty.
  • Time: O(k log k)—k heap operations, log k for heap size.
  • Space: O(k)—heap and seen set store up to k pairs.

This is like a smart pair picker—grab the smallest sums efficiently!

Alternative Solution: Brute Force

Section link icon

Why an Alternative Approach?

The brute force solution runs in O(mn log (mn)) time by generating all possible pairs, computing their sums, and sorting to pick the k smallest. It’s slower and uses more space—great for small inputs or understanding the full scope!

How It Works

  • Generate: Create all m*n pairs.
  • Sort: Sort by sum.
  • Select: Take first k pairs.

Step-by-Step Example

For nums1 = [1,7,11], nums2 = [2,4,6], k = 3:

  • Pairs:
    • (1,2)=3, (1,4)=5, (1,6)=7, (7,2)=9, (7,4)=11, (7,6)=13, (11,2)=13, (11,4)=15, (11,6)=17.
  • Sort: [3, 5, 7, 9, 11, 13, 13, 15, 17].
  • Take k=3: [3, 5, 7] → [[1,2], [1,4], [1,6]].

Code with Explanation

class Solution:
    def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:
        if not nums1 or not nums2:
            return []

        # Generate all pairs
        pairs = []
        for i in range(len(nums1)):
            for j in range(len(nums2)):
                pairs.append([nums1[i], nums2[j]])

        # Sort by sum
        pairs.sort(key=lambda x: x[0] + x[1])

        # Return k smallest
        return pairs[:min(k, len(pairs))]

Explanation

  • Lines 6-10: Generate all pairs (u, v) in a list.
  • Line 12: Sort pairs by sum using a lambda function.
  • Line 14: Return first k pairs (or all if fewer).
  • Time: O(m*n log (m*n))—sorting dominates.
  • Space: O(m*n)—stores all pairs.

It’s like listing everything and picking the best—simple but heavy!

Comparing the Two Solutions

Section link icon
  • Min-Heap (Best):
    • Time: O(k log k)—heap ops.
    • Space: O(k)—heap size.
    • Pros: Fast, space-efficient.
    • Cons: Heap logic less intuitive.
  • Brute Force (Alternative):
    • Time: O(m*n log (m*n))—sort all pairs.
    • Space: O(m*n)—all pairs.
    • Pros: Easy to code.
    • Cons: Slow, memory-intensive.

Min-heap wins for efficiency!

Additional Examples and Edge Cases

Section link icon
  • nums1=[1], nums2=[1], k=1: [[1,1]].
  • nums1=[1,2], nums2=[], k=1: [].
  • Large k: Min-heap scales better.

Both work, min-heap is faster.

Complexity Breakdown

Section link icon
  • Min-Heap:
    • Time: O(k log k).
    • Space: O(k).
  • Brute Force:
    • Time: O(m*n log (m*n)).
    • Space: O(m*n).

Min-heap excels for performance.

Key Takeaways

Section link icon
  • Min-Heap: Pick smartly—fast and lean!
  • Brute Force: List all—clear but slow!
  • Pairs: Optimization is key.
  • Python Tip: Heapq rocks—see [Python Basics](/python/basics).

Final Thoughts: Pair Those Sums

Section link icon

LeetCode 373: Find K Pairs with Smallest Sums in Python is a pairing challenge. The min-heap solution is the efficiency champ, while brute force builds intuition. Want more? Try LeetCode 215: Kth Largest Element or LeetCode 378: Kth Smallest Element in a Sorted Matrix. Ready to pair? Visit Solve LeetCode 373 on LeetCode and find those sums today!