🧠
Min Heap Merge (Merge k Sorted Lists)
💡 This approach leverages the sorted rows by merging them using a min heap, similar to merging k sorted lists. It is more efficient and uses the matrix’s sorted property.
Intuition
Use a min heap to keep track of the smallest unvisited elements from each row. Extract the smallest element k times to find the kth smallest.
Algorithm
- Initialize a min heap and push the first element of each row along with its coordinates.
- Pop the smallest element from the heap.
- If there is a next element in the same row, push it into the heap.
- Repeat steps 2-3 k times; the last popped element is the kth smallest.
💡 The heap always contains the next smallest candidates from each row, ensuring efficient selection.
import heapq
def kthSmallest(matrix, k):
n = len(matrix)
min_heap = []
for r in range(min(k, n)):
heapq.heappush(min_heap, (matrix[r][0], r, 0))
count = 0
while min_heap:
val, r, c = heapq.heappop(min_heap)
count += 1
if count == k:
return val
if c + 1 < n:
heapq.heappush(min_heap, (matrix[r][c+1], r, c+1))
# Driver code
if __name__ == '__main__':
matrix = [[1,5,9],[10,11,13],[12,13,15]]
k = 8
print(kthSmallest(matrix, k)) # Output: 13
Line Notes
import heapqImport heapq for min heap operations
for r in range(min(k, n))Push first element of up to k rows to limit heap size
heapq.heappush(min_heap, (matrix[r][0], r, 0))Push tuple with value and coordinates
val, r, c = heapq.heappop(min_heap)Pop smallest element from heap
if c + 1 < n:If next element in row exists, push it to heap
import java.util.*;
public class Solution {
public static int kthSmallest(int[][] matrix, int k) {
int n = matrix.length;
PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
for (int r = 0; r < Math.min(k, n); r++) {
minHeap.offer(new int[]{matrix[r][0], r, 0});
}
int count = 0;
while (!minHeap.isEmpty()) {
int[] curr = minHeap.poll();
int val = curr[0], r = curr[1], c = curr[2];
count++;
if (count == k) return val;
if (c + 1 < n) {
minHeap.offer(new int[]{matrix[r][c + 1], r, c + 1});
}
}
return -1; // Should never reach here
}
public static void main(String[] args) {
int[][] matrix = {{1,5,9},{10,11,13},{12,13,15}};
int k = 8;
System.out.println(kthSmallest(matrix, k)); // Output: 13
}
}
Line Notes
PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]))Min heap ordered by element value
for (int r = 0; r < Math.min(k, n); r++)Add first element of each row up to k rows
minHeap.offer(new int[]{matrix[r][0], r, 0})Store value and coordinates in heap
int[] curr = minHeap.poll()Extract smallest element from heap
if (c + 1 < n)Add next element in the same row if exists
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int kthSmallest(vector<vector<int>>& matrix, int k) {
int n = matrix.size();
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 r = 0; r < min(k, n); r++) {
minHeap.emplace(matrix[r][0], r, 0);
}
int count = 0;
while (!minHeap.empty()) {
auto [val, r, c] = minHeap.top();
minHeap.pop();
count++;
if (count == k) return val;
if (c + 1 < n) {
minHeap.emplace(matrix[r][c + 1], r, c + 1);
}
}
return -1; // Should not reach here
}
int main() {
vector<vector<int>> matrix = {{1,5,9},{10,11,13},{12,13,15}};
int k = 8;
cout << kthSmallest(matrix, k) << endl; // Output: 13
return 0;
}
Line Notes
auto cmp = [](const tuple<int,int,int>& a, const tuple<int,int,int>& b)Comparator for min heap by value
priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, decltype(cmp)> minHeap(cmp)Declare min heap with custom comparator
minHeap.emplace(matrix[r][0], r, 0)Push first element of each row with coordinates
auto [val, r, c] = minHeap.top()Extract smallest element tuple
if (c + 1 < n)Push next element in the same row if exists
class MinHeap {
constructor() {
this.heap = [];
}
swap(i, j) {
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
}
push(val) {
this.heap.push(val);
this.bubbleUp();
}
bubbleUp() {
let idx = this.heap.length - 1;
while (idx > 0) {
let parent = Math.floor((idx - 1) / 2);
if (this.heap[parent][0] <= this.heap[idx][0]) break;
this.swap(parent, idx);
idx = parent;
}
}
pop() {
if (this.heap.length === 0) return undefined;
if (this.heap.length === 1) return this.heap.pop();
const top = this.heap[0];
this.heap[0] = this.heap.pop();
this.bubbleDown();
return top;
}
bubbleDown() {
let idx = 0;
const length = this.heap.length;
while (true) {
let left = 2 * idx + 1;
let right = 2 * idx + 2;
let smallest = idx;
if (left < length && this.heap[left][0] < this.heap[smallest][0]) smallest = left;
if (right < length && this.heap[right][0] < this.heap[smallest][0]) smallest = right;
if (smallest === idx) break;
this.swap(idx, smallest);
idx = smallest;
}
}
size() {
return this.heap.length;
}
}
function kthSmallest(matrix, k) {
const n = matrix.length;
const minHeap = new MinHeap();
for (let r = 0; r < Math.min(k, n); r++) {
minHeap.push([matrix[r][0], r, 0]);
}
let count = 0;
while (minHeap.size() > 0) {
const [val, r, c] = minHeap.pop();
count++;
if (count === k) return val;
if (c + 1 < n) {
minHeap.push([matrix[r][c + 1], r, c + 1]);
}
}
return -1; // Fallback, should not reach here
}
// Test
const matrix = [[1,5,9],[10,11,13],[12,13,15]];
const k = 8;
console.log(kthSmallest(matrix, k)); // Output: 13
Line Notes
class MinHeapCustom min heap implementation to manage elements
minHeap.push([matrix[r][0], r, 0])Push first element of each row with coordinates
const [val, r, c] = minHeap.pop()Pop smallest element from heap
if (count === k) return valReturn kth smallest when count matches
if (c + 1 < n)Push next element in the same row if exists
Heap size is at most n, each of k pops and pushes costs log n, total O(k log n).
💡 For n=300 and k=1000, this is much faster than sorting all elements.
Interview Verdict: Accepted and efficient for medium-sized inputs
This approach balances simplicity and efficiency, making it a strong candidate in interviews.