🧠
Optimized Min-Heap with Early Termination
💡 This approach is a refinement of the previous heap method, adding early termination and limiting initial heap size to improve performance.
Intuition
Only initialize the heap with the first min(k, len(nums1)) pairs, and stop as soon as k pairs are found, avoiding unnecessary heap operations.
Algorithm
- Initialize a min-heap with pairs (nums1[i], nums2[0]) for i in [0, min(k, len(nums1))].
- Pop the smallest pair from the heap and add it to the result.
- If the next element in nums2 exists for the popped pair, push it into the heap.
- Stop when k pairs are collected or heap is empty.
💡 This approach avoids pushing unnecessary pairs and terminates early, improving runtime.
from typing import List
import heapq
def kSmallestPairs(nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:
if not nums1 or not nums2 or k == 0:
return []
min_heap = []
result = []
n1, n2 = len(nums1), len(nums2)
for i in range(min(k, n1)):
heapq.heappush(min_heap, (nums1[i] + nums2[0], i, 0))
while min_heap and len(result) < k:
current_sum, i, j = heapq.heappop(min_heap)
result.append([nums1[i], nums2[j]])
if j + 1 < n2:
heapq.heappush(min_heap, (nums1[i] + nums2[j+1], i, j+1))
return result
# Example usage
if __name__ == '__main__':
print(kSmallestPairs([1,7,11], [2,4,6], 3))
Line Notes
n1, n2 = len(nums1), len(nums2)Store lengths to avoid repeated calls
for i in range(min(k, n1))Limit initial heap size to k or nums1 length
heapq.heappush(min_heap, (nums1[i] + nums2[0], i, 0))Push initial pairs to heap
while min_heap and len(result) < kStop early when k pairs collected
current_sum, i, j = heapq.heappop(min_heap)Extract smallest sum pair
if j + 1 < n2Check if next element in nums2 exists
heapq.heappush(min_heap, (nums1[i] + nums2[j+1], i, j+1))Push next candidate pair
import java.util.*;
public class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
List<List<Integer>> result = new ArrayList<>();
int n1 = nums1.length, n2 = nums2.length;
if (n1 == 0 || n2 == 0 || k == 0) return result;
PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
for (int i = 0; i < Math.min(k, n1); i++) {
minHeap.offer(new int[]{nums1[i] + nums2[0], i, 0});
}
while (k > 0 && !minHeap.isEmpty()) {
int[] cur = minHeap.poll();
int i = cur[1], j = cur[2];
result.add(Arrays.asList(nums1[i], nums2[j]));
if (j + 1 < n2) {
minHeap.offer(new int[]{nums1[i] + nums2[j + 1], i, j + 1});
}
k--;
}
return result;
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.kSmallestPairs(new int[]{1,7,11}, new int[]{2,4,6}, 3));
}
}
Line Notes
int n1 = nums1.length, n2 = nums2.length;Store lengths for efficiency
if (n1 == 0 || n2 == 0 || k == 0) return result;Handle edge cases early
for (int i = 0; i < Math.min(k, n1); i++)Limit initial heap size
minHeap.offer(new int[]{nums1[i] + nums2[0], i, 0});Push initial pairs
while (k > 0 && !minHeap.isEmpty())Stop early when k pairs collected
if (j + 1 < n2)Check if next element in nums2 exists
minHeap.offer(new int[]{nums1[i] + nums2[j + 1], i, j + 1});Push next candidate pair
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
vector<vector<int>> result;
int n1 = nums1.size(), n2 = nums2.size();
if (n1 == 0 || n2 == 0 || k == 0) return result;
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 < min(n1, k); i++) {
minHeap.emplace(nums1[i] + nums2[0], i, 0);
}
while (k-- > 0 && !minHeap.empty()) {
auto [sum, i, j] = minHeap.top();
minHeap.pop();
result.push_back({nums1[i], nums2[j]});
if (j + 1 < n2) {
minHeap.emplace(nums1[i] + nums2[j + 1], i, j + 1);
}
}
return result;
}
int main() {
vector<int> nums1 = {1,7,11};
vector<int> nums2 = {2,4,6};
int k = 3;
vector<vector<int>> res = kSmallestPairs(nums1, nums2, k);
for (auto &p : res) {
cout << '[' << p[0] << ',' << p[1] << ']';
}
cout << '\n';
return 0;
}
Line Notes
int n1 = nums1.size(), n2 = nums2.size();Store lengths for efficiency
if (n1 == 0 || n2 == 0 || k == 0) return result;Handle edge cases early
for (int i = 0; i < min(n1, k); i++)Limit initial heap size
minHeap.emplace(nums1[i] + nums2[0], i, 0);Push initial pairs
while (k-- > 0 && !minHeap.empty())Stop early when k pairs collected
if (j + 1 < n2)Check if next element in nums2 exists
minHeap.emplace(nums1[i] + nums2[j + 1], i, j + 1);Push next candidate pair
function kSmallestPairs(nums1, nums2, k) {
if (nums1.length === 0 || nums2.length === 0 || k === 0) return [];
const minHeap = new MinPriorityQueue({priority: x => x.sum});
const result = [];
const n1 = nums1.length, n2 = nums2.length;
for (let i = 0; i < Math.min(k, n1); i++) {
minHeap.enqueue({sum: nums1[i] + nums2[0], i: i, j: 0});
}
while (k > 0 && !minHeap.isEmpty()) {
const {element} = minHeap.dequeue();
const {i, j} = element;
result.push([nums1[i], nums2[j]]);
if (j + 1 < n2) {
minHeap.enqueue({sum: nums1[i] + nums2[j + 1], i: i, j: j + 1});
}
k--;
}
return result;
}
// Example usage
// console.log(kSmallestPairs([1,7,11], [2,4,6], 3));
Line Notes
const n1 = nums1.length, n2 = nums2.length;Store lengths for efficiency
if (nums1.length === 0 || nums2.length === 0 || k === 0) return [];Handle edge cases early
for (let i = 0; i < Math.min(k, n1); i++)Limit initial heap size
minHeap.enqueue({sum: nums1[i] + nums2[0], i: i, j: 0});Push initial pairs
while (k > 0 && !minHeap.isEmpty())Stop early when k pairs collected
if (j + 1 < n2)Check if next element in nums2 exists
minHeap.enqueue({sum: nums1[i] + nums2[j + 1], i: i, j: j + 1});Push next candidate pair
Same as previous approach but with early termination to avoid unnecessary work.
💡 This approach is the most efficient practical solution for large inputs.
Interview Verdict: Accepted and preferred in interviews
This is the best approach to implement in interviews for this problem.