Find K Pairs With Smallest Sums

8 min read

Find K Pairs with Smallest Sums: A Complete Guide

Finding k pairs with smallest sums is a classic algorithmic problem that appears frequently in coding interviews and competitive programming. The problem challenges you to identify k pairs of elements from two sorted arrays such that the sum of each pair is minimized. Understanding this problem not only helps you ace technical interviews but also builds a strong foundation in data structures like heaps and priority queues Turns out it matters..

Problem Statement

Given two sorted integer arrays nums1 and nums2, and an integer k, the goal is to find the k pairs (u, v) where u belongs to nums1 and v belongs to nums2, such that the sum u + v is as small as possible.

As an example, if nums1 = [1, 7, 11] and nums2 = [2, 4, 6] with k = 3, the output should be [[1, 2], [1, 4], [1, 6]] because these pairs have the smallest sums of 3, 5, and 7 respectively.

Brute Force Approach

The most straightforward way to solve this problem is to generate all possible pairs, calculate their sums, sort them, and return the first k pairs Most people skip this — try not to..

Steps:

  1. Create an empty list to store all pairs along with their sums.
  2. Use nested loops to iterate through both arrays.
  3. For each combination, calculate the sum and store the pair with its sum.
  4. Sort the list based on the sum values.
  5. Return the first k elements from the sorted list.

While this approach is easy to understand, it has significant drawbacks. Which means the time complexity becomes O(m × n × log(m × n)) where m and n are the lengths of the two arrays. The space complexity is also O(m × n) because we need to store all possible pairs. This makes the brute force method impractical for large input sizes.

Optimized Approach Using Min Heap

A much more efficient solution uses a min heap (priority queue) to keep track of the smallest sum pairs without generating all possible combinations upfront.

Algorithm Steps

  1. Initialize a min heap and push the first k pairs formed by pairing each element from nums1 with the first element of nums2.
  2. Each heap entry should contain the sum, the index from nums1, and the index from nums2.
  3. Pop the smallest element from the heap and add it to the result list.
  4. After popping an element at position (i, j), push the next candidate pair (i, j+1) into the heap if j+1 is within bounds.
  5. Repeat steps 3 and 4 until you have collected k pairs or the heap becomes empty.

Why This Works

The heap approach leverages the fact that both arrays are sorted. Practically speaking, by always expanding the next possible candidate from the array with the smaller current element, we check that we explore pairs in ascending order of their sums. This is similar to the merge step in merge sort but extended to two dimensions.

Two Pointers Approach

Another elegant solution uses a variation of the k-way merge algorithm with pointers.

  1. Start with pointers at the beginning of both arrays.
  2. Use a min heap to track the current smallest sum pair.
  3. When you extract a pair (i, j) from the heap, push (i+1, j) and (i, j+1) if they haven't been visited yet.
  4. Use a visited set to avoid processing the same pair multiple times.

This approach ensures that each pair is processed exactly once, and the heap always contains the next smallest candidates.

Complexity Analysis

Time Complexity:

  • Brute force: O(m × n × log(m × n))
  • Heap approach: O(k × log k) since we perform at most k heap operations, each taking O(log k) time.

Space Complexity:

  • Brute force: O(m × n) for storing all pairs.
  • Heap approach: O(k) for the heap and result storage.

The heap-based solution is clearly superior for large datasets where m and n can be in the thousands or millions Surprisingly effective..

Python Implementation

Here is a clean implementation using the heap approach:

import heapq

def kSmallestPairs(nums1, nums2, k):
    if not nums1 or not nums2:
        return []
    
    heap = []
    result = []
    
    # Initialize heap with pairs from nums1 and first element of nums2
    for i in range(min(k, len(nums1))):
        heapq.Now, heappush(heap, (nums1[i] + nums2[0], i, 0))
    
    while heap and len(result) < k:
        sum_val, i, j = heapq. heappop(heap)
        result.append([nums1[i], nums2[j]])
        
        # Push next pair from nums2 if available
        if j + 1 < len(nums2):
            heapq.

## Edge Cases to Consider

When implementing this solution, watch out for these common pitfalls:

- **Empty arrays:** If either array is empty, return an empty list immediately.
- **k larger than total pairs:** If k exceeds the total number of possible pairs (m × n), return all possible pairs.
- **Duplicate sums:** Multiple pairs might have the same sum; the algorithm handles this naturally through the heap ordering.
- **Single element arrays:** When one array has only one element, the solution simplifies to pairing that element with the first k elements of the other array.

## Real-World Applications

This algorithm has practical applications beyond coding interviews:

- **Recommendation systems:** Finding the k closest matches between two sets of items based on similarity scores.
- **Resource allocation:** Pairing tasks with workers where the sum represents cost or time.
- **Financial modeling:** Identifying optimal pairs of investments with minimum combined risk.
- **Logistics:** Matching delivery locations with vehicles to minimize total distance.

## Common Mistakes

Many developers make these errors when solving this problem:

1. **Not handling the visited set properly** in the two pointers approach, leading to duplicate pairs in the result.
2. **Pushing too many elements** into the heap initially, which defeats the purpose of optimization.
3. **Forgetting to check array bounds** when pushing new candidates into the heap.
4. **Assuming both arrays are the same size** when the problem statement doesn't guarantee this.

## Testing Your Solution

To verify your implementation, test with these cases:

- `nums1 = [1, 2], nums2 = [3], k = 3` should return `[[1, 3], [2, 3]]`
- `nums1 = [1, 1, 2], nums2 = [1, 2, 3], k = 2` should return `[[1, 1], [1, 1]]`
- `nums1 =

```python
def kSmallestPairs(nums1, nums2, k):
    if not nums1 or not nums2 or k <= 0:
        return []
    
    heap = []
    result = []
    
    # Initialize heap with pairs from nums1 and first element of nums2
    for i in range(min(k, len(nums1))):
        heapq.heappush(heap, (nums1[i] + nums2[0], i, 0))
    
    while heap and len(result) < k:
        sum_val, i, j = heapq.heappop(heap)
        result.append([nums1[i], nums2[j]])
        
        # Push next pair from nums2 if available
        if j + 1 < len(nums2):
            heapq.heappush(heap, (nums1[i] + nums2[j+1], i, j+1))
    
    return result

# Test cases
print(kSmallestPairs([1, 2], [3], 3))  # Expected: [[1, 3], [2, 3]]
print(kSmallestPairs([1, 1, 2], [1, 2, 3], 2))  # Expected: [[1, 1], [1, 1]]
print(kSmallestPairs([], [1, 2], 1))  # Expected: []
print(kSmallestPairs([1, 2], [], 1))  # Expected: []
print(kSmallestPairs([1, 2, 3], [4, 5, 6], 10))  # Expected: all pairs sorted by sum

Time and Space Complexity Analysis

The heap-based approach offers optimal performance characteristics:

Time Complexity: O(k log(min(m, n))) where m and n are the lengths of nums1 and nums2 respectively. This is because we perform at most k heap operations, and the heap size never exceeds min(m, n) Most people skip this — try not to. Which is the point..

Space Complexity: O(min(m, n)) for the heap storage Worth keeping that in mind..

This is significantly better than the brute force approach which would require O(m × n) space to store all pairs and O(m × n log(m × n)) time to sort them.

Alternative Approaches

While the heap approach is optimal, other solutions exist:

Two Pointers with Min-Heap: Maintain pointers for each row and use a heap to track minimum sums. On the flip side, this requires careful handling of visited states to avoid duplicates.

Binary Search: Can be used to find the kth smallest sum, then count pairs with sums less than or equal to that value. This approach has different trade-offs and is more complex to implement correctly The details matter here..

Merge K Sorted Arrays: Treat each row as a sorted array and merge them efficiently It's one of those things that adds up..

Each approach has its merits depending on the specific constraints and requirements of the problem.

Conclusion

The k smallest pairs problem beautifully demonstrates the power of heap data structures in algorithmic problem-solving. By leveraging a min-heap to always extract the minimum sum pair efficiently, we achieve an elegant solution that balances time and space complexity optimally.

The key insights are recognizing that we don't need to generate all possible pairs upfront, and that we can incrementally build our result by always considering the next smallest valid pair. This incremental approach, combined with careful boundary checking, makes the solution both efficient and dependable.

Understanding this problem provides valuable experience in working with heaps, handling edge cases, and thinking about optimization strategies that avoid unnecessary computation. These skills translate well to many other algorithmic challenges and real-world applications where efficiency matters It's one of those things that adds up..

Freshly Posted

Just Released

See Where It Goes

Same Topic, More Views

Thank you for reading about Find K Pairs With Smallest Sums. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home