Given a 2D matrix, mat[][] consisting of sorted arrays, where each row is sorted in non-decreasing order, find a single sorted array that contains all the elements from the matrix.
Examples:
Input: mat[][] = [[1, 3, 5, 7], [2, 4, 6, 8], [0, 9, 10, 11]]
Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Explanation: Merging all elements from the 3 sorted arrays and sorting them results in: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].
Input: mat[][] = [[1, 2, 3, 4], [2, 2, 3, 4], [5, 5, 6, 6], [7, 8, 9, 9]]
Output: [1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 9]
Explanation: Merging all elements from the 4 sorted arrays and sorting them results in:[1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 9] .
[Naive Approach] Concatenate all and Sort
The idea is to merges sorted arrays by first flattening all the arrays into a single one-dimensional vector. Then sorts this combined vector using the standard sorting algorithm (sort() from the STL). This ensures the final output is a fully sorted array containing all elements from the input arrays.
C++
//Driver Code Starts
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
//Driver Code Ends
vector<int> mergeArrays(vector<vector<int>>& mat) {
vector<int> res;
// Append all arrays into res
for (const auto& vec : mat) {
for (int val : vec)
res.push_back(val);
}
// Sort the res
sort(res.begin(), res.end());
return res;
}
//Driver Code Starts
int main() {
vector<vector<int>> mat = {{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}};
vector<int> res = mergeArrays(mat);
for (int val : res) {
cout << val << " ";
}
return 0;
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.Collections;
class GfG {
//Driver Code Ends
static ArrayList<Integer> mergeArrays(int[][] mat) {
ArrayList<Integer> res = new ArrayList<>();
// Append all arrays into res
for (int i = 0; i < mat.length; i++) {
for (int j = 0; j < mat[i].length; j++) {
res.add(mat[i][j]);
}
}
// Sort the res
Collections.sort(res);
return res;
}
//Driver Code Starts
public static void main(String[] args) {
int[][] mat = {
{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}
};
ArrayList<Integer> res = mergeArrays(mat);
for (int val : res) {
System.out.print(val + " ");
}
}
}
//Driver Code Ends
Python
def mergeArrays(mat):
res = []
# Append all arrays into res
for vec in mat:
for val in vec:
res.append(val)
# Sort the res
res.sort()
return res
if __name__ == "__main__":
#Driver Code Starts
mat = [[1, 3, 5, 7],
[2, 4, 6, 8],
[0, 9, 10, 11]]
res = mergeArrays(mat)
print(*res)
#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;
class GFG {
//Driver Code Ends
static List<int> mergeArrays(int[,] mat) {
List<int> res = new List<int>();
int rows = mat.GetLength(0);
int cols = mat.GetLength(1);
// Append all elements into res
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
res.Add(mat[i, j]);
}
}
// Sort the res
res.Sort();
return res;
}
//Driver Code Starts
static void Main() {
int[,] mat = new int[,] {
{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}
};
List<int> res = mergeArrays(mat);
foreach (int val in res) {
Console.Write(val + " ");
}
}
}
//Driver Code Ends
JavaScript
function mergeArrays(mat) {
let res = [];
// Append all arrays into res
for (let vec of mat) {
for (let val of vec) {
res.push(val);
}
}
// Sort the res
res.sort((a, b) => a - b);
return res;
}
// Driver code
//Driver Code Starts
let mat = [
[1, 3, 5, 7],
[2, 4, 6, 8],
[0, 9, 10, 11]
];
let res = mergeArrays(mat);
console.log(res.join(" "));
//Driver Code Ends
Output0 1 2 3 4 5 6 7 8 9 10 11
Time Complexity: O(n log(n)), where n is total number of elements
Auxiliary Space: O(1)
[Expected Approach 1] Using Merge Sort - Works Better for Equal Sized Arrays
The idea is to use the Divide and Conquer approach, similar to Merge Sort. We keep dividing the given sorted arrays into smaller groups until we are left with single array. Then, we start merging these single arrays upward in sorted order, gradually combining them until one fully sorted array remains.
C++
//Driver Code Starts
#include <iostream>
#include <vector>
using namespace std;
//Driver Code Ends
// Function to merge two sorted arrays
vector<int> concat(vector<int> &a, vector<int> &b) {
int i = 0, j = 0;
int n1 = a.size(), n2 = b.size();
vector<int> c;
c.reserve(n1 + n2);
// Merge both arrays in sorted order
while (i < n1 && j < n2) {
if (a[i] < b[j])
c.push_back(a[i++]);
else
c.push_back(b[j++]);
}
// Add remaining elements of first array
while (i < n1)
c.push_back(a[i++]);
// Add remaining elements of second array
while (j < n2)
c.push_back(b[j++]);
return c;
}
// Recursively merge K sorted arrays using divide and conquer
vector<int> merge(vector<vector<int>> &mat, int lo, int hi) {
// Base case
if (lo == hi)
return mat[lo];
// Divide arrays into two halves
int mid = (lo + hi) / 2;
// Merge left half
vector<int> left = merge(mat, lo, mid);
// Merge right half
vector<int> right = merge(mat, mid + 1, hi);
// Combine both halves
return concat(left, right);
}
// merge all K sorted arrays
vector<int> mergeArrays(vector<vector<int>> &mat) {
int k = mat.size();
if (k == 0)
return {};
return merge(mat, 0, k - 1);
}
//Driver Code Starts
int main() {
vector<vector<int>> mat = {
{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}
};
int k = mat.size();
vector<int> res = mergeArrays(mat);
for (int val : res)
cout << val << " ";
cout << endl;
return 0;
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
class GFG {
//Driver Code Ends
// Function to merge two sorted arrays
static ArrayList<Integer> concat(ArrayList<Integer> a, ArrayList<Integer> b) {
int i = 0, j = 0;
int n1 = a.size(), n2 = b.size();
ArrayList<Integer> c = new ArrayList<>();
// Merge both arrays in sorted order
while (i < n1 && j < n2) {
if (a.get(i) < b.get(j))
c.add(a.get(i++));
else
c.add(b.get(j++));
}
// Add remaining elements of first array
while (i < n1)
c.add(a.get(i++));
// Add remaining elements of second array
while (j < n2)
c.add(b.get(j++));
return c;
}
// Recursively merge K sorted arrays using divide and conquer
static ArrayList<Integer> merge(ArrayList<ArrayList<Integer>> mat, int lo, int hi) {
// Base case
if (lo == hi)
return mat.get(lo);
// Divide arrays into two halves
int mid = (lo + hi) / 2;
// Merge left half
ArrayList<Integer> left = merge(mat, lo, mid);
// Merge right half
ArrayList<Integer> right = merge(mat, mid + 1, hi);
// Combine both halves
return concat(left, right);
}
// merge all K sorted arrays
static ArrayList<Integer> mergeArrays(int[][] mat) {
int k = mat.length;
if (k == 0)
return new ArrayList<>();
// Convert 2D array to ArrayList<ArrayList<Integer>>
ArrayList<ArrayList<Integer>> list = new ArrayList<>();
for (int i = 0; i < k; i++) {
ArrayList<Integer> temp = new ArrayList<>();
for (int j = 0; j < mat[i].length; j++) {
temp.add(mat[i][j]);
}
list.add(temp);
}
return merge(list, 0, k - 1);
}
//Driver Code Starts
public static void main(String[] args) {
int[][] mat = {
{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}
};
ArrayList<Integer> res = mergeArrays(mat);
for (int val : res)
System.out.print(val + " ");
System.out.println();
}
}
//Driver Code Ends
Python
# Function to merge two sorted arrays
def concat(a, b):
i = 0
j = 0
n1 = len(a)
n2 = len(b)
c = []
# Merge both arrays in sorted order
while i < n1 and j < n2:
if a[i] < b[j]:
c.append(a[i])
i += 1
else:
c.append(b[j])
j += 1
# Add remaining elements of first array
while i < n1:
c.append(a[i])
i += 1
# Add remaining elements of second array
while j < n2:
c.append(b[j])
j += 1
return c
# Recursively merge K sorted arrays using divide and conquer
def merge(mat, lo, hi):
# Base case
if lo == hi:
return mat[lo]
# Divide arrays into two halves
mid = (lo + hi) // 2
# Merge left half
left = merge(mat, lo, mid)
# Merge right half
right = merge(mat, mid + 1, hi)
# Combine both halves
return concat(left, right)
# merge all K sorted arrays
def mergeArrays(mat):
k = len(mat)
if k == 0:
return []
return merge(mat, 0, k - 1)
if __name__ == "__main__":
#Driver Code Starts
mat = [
[1, 3, 5, 7],
[2, 4, 6, 8],
[0, 9, 10, 11]
]
k = len(mat)
res = mergeArrays(mat)
for val in res:
print(val, end=" ")
print()
#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;
class GFG {
//Driver Code Ends
// Function to merge two sorted arrays
static List<int> concat(List<int> a, List<int> b)
{
int i = 0, j = 0;
int n1 = a.Count, n2 = b.Count;
List<int> c = new List<int>(n1 + n2);
// Merge both arrays in sorted order
while (i < n1 && j < n2)
{
if (a[i] < b[j])
c.Add(a[i++]);
else
c.Add(b[j++]);
}
// Add remaining elements of first array
while (i < n1)
c.Add(a[i++]);
// Add remaining elements of second array
while (j < n2)
c.Add(b[j++]);
return c;
}
// Recursively merge K sorted arrays using divide and conquer
static List<int> merge(List<List<int>> mat, int lo, int hi)
{
// Base case
if (lo == hi)
return mat[lo];
// Divide arrays into two halves
int mid = (lo + hi) / 2;
// Merge left half
List<int> left = merge(mat, lo, mid);
// Merge right half
List<int> right = merge(mat, mid + 1, hi);
// Combine both halves
return concat(left, right);
}
// merge all K sorted arrays
static List<int> mergeArrays(int[,] mat)
{
int k = mat.GetLength(0);
if (k == 0)
return new List<int>();
int nCols = mat.GetLength(1);
// Convert 2D array to List<List<int>>
List<List<int>> list = new List<List<int>>();
for (int i = 0; i < k; i++)
{
List<int> temp = new List<int>();
for (int j = 0; j < nCols; j++)
{
temp.Add(mat[i, j]);
}
list.Add(temp);
}
return merge(list, 0, k - 1);
}
//Driver Code Starts
static void Main(string[] args)
{
int[,] mat = new int[,]
{
{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}
};
List<int> res = mergeArrays(mat);
foreach (int val in res)
Console.Write(val + " ");
Console.WriteLine();
}
}
//Driver Code Ends
JavaScript
// Function to merge two sorted arrays
function concat(a, b) {
let i = 0, j = 0;
let n1 = a.length, n2 = b.length;
let c = [];
// Merge both arrays in sorted order
while (i < n1 && j < n2) {
if (a[i] < b[j])
c.push(a[i++]);
else
c.push(b[j++]);
}
// Add remaining elements of first array
while (i < n1)
c.push(a[i++]);
// Add remaining elements of second array
while (j < n2)
c.push(b[j++]);
return c;
}
// Recursively merge K sorted arrays using divide and conquer
function merge(mat, lo, hi) {
// Base case
if (lo === hi)
return mat[lo];
// Divide arrays into two halves
let mid = Math.floor((lo + hi) / 2);
// Merge left half
let left = merge(mat, lo, mid);
// Merge right half
let right = merge(mat, mid + 1, hi);
// Combine both halves
return concat(left, right);
}
// merge all K sorted arrays
function mergeArrays(mat) {
let k = mat.length;
if (k === 0)
return [];
return merge(mat, 0, k - 1);
}
// Driver code
//Driver Code Starts
let mat = [
[1, 3, 5, 7],
[2, 4, 6, 8],
[0, 9, 10, 11]
];
let k = mat.length;
let res = mergeArrays(mat);
console.log(res.join(' '));
//Driver Code Ends
Output0 1 2 3 4 5 6 7 8 9 10 11
Time Complexity: O(n*logk), k is number of rows and n is total number of elements.
Auxiliary Space: O(n)
[Expected Approach 2] Using Min-Heap - Works better for Different Sized Arrays
The idea is to merge sorted arrays using a Min Heap. We start by inserting the first element of each array into the heap. The smallest element is always at the top, so we remove it and add it to the output array. Then we insert the next element from the same array into the heap. We repeat this process until the heap is empty. This ensures that we always pick the smallest available element, producing a fully sorted merged array efficiently.
C++
//Driver Code Starts
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
//Driver Code Ends
vector<int> mergeArrays(vector<vector<int>> &mat){
int k = mat.size();
vector<int> output;
// Min-heap: {value, {array index, element index}}
priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>,
greater<pair<int, pair<int, int>>>> minHeap;
// Push first element of each array
for (int i = 0; i < k; ++i){
if (!mat[i].empty()){
minHeap.push({mat[i][0], {i, 0}});
}
}
// Merge all elements
while (!minHeap.empty()){
auto top = minHeap.top();
minHeap.pop();
int val = top.first;
int i = top.second.first;
int j = top.second.second;
output.push_back(val);
// Push next element from same array
if (j + 1 < mat[i].size()){
minHeap.push({mat[i][j + 1], {i, j + 1}});
}
}
return output;
}
//Driver Code Starts
int main(){
vector<vector<int>> mat= {{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}};
vector<int> result = mergeArrays(mat);
for (int x : result){
cout << x << " ";
}
cout << endl;
return 0;
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Comparator;
class GFG {
//Driver Code Ends
static ArrayList<Integer> mergeArrays(int[][] mat){
int k = mat.length;
ArrayList<Integer> output = new ArrayList<>();
// Min-heap: {value, {array index, element index}}
PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
// Push first element of each array
for (int i = 0; i < k; ++i){
if (mat[i].length > 0){
minHeap.add(new int[]{mat[i][0], i, 0});
}
}
// Merge all elements
while (!minHeap.isEmpty()){
int[] top = minHeap.poll();
int val = top[0];
int i = top[1];
int j = top[2];
output.add(val);
// Push next element from same array
if (j + 1 < mat[i].length){
minHeap.add(new int[]{mat[i][j + 1], i, j + 1});
}
}
return output;
}
//Driver Code Starts
public static void main(String[] args){
int[][] mat = {
{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}
};
ArrayList<Integer> result = mergeArrays(mat);
for (int x : result){
System.out.print(x + " ");
}
System.out.println();
}
}
//Driver Code Ends
Python
#Driver Code Starts
import heapq
#Driver Code Ends
def mergeArrays(mat):
k = len(mat)
output = []
# Min-heap: (value, (array index, element index))
minHeap = []
# Push first element of each array
for i in range(k):
if len(mat[i]) > 0:
heapq.heappush(minHeap, (mat[i][0], i, 0))
# Merge all elements
while minHeap:
val, i, j = heapq.heappop(minHeap)
output.append(val)
# Push next element from same array
if j + 1 < len(mat[i]):
heapq.heappush(minHeap, (mat[i][j + 1], i, j + 1))
return output
#Driver Code Starts
if __name__ == "__main__":
mat = [
[1, 3, 5, 7],
[2, 4, 6, 8],
[0, 9, 10, 11]
]
result = mergeArrays(mat)
print(" ".join(map(str, result)))
#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;
// Custom Min-Heap Priority Queue
class MinHeap {
private List<(int val, int arrIdx, int elemIdx)> heap;
public MinHeap()
{
heap = new List<(int, int, int)>();
}
private void Swap(int i, int j)
{
var temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
private void HeapifyUp(int index)
{
while (index > 0)
{
int parent = (index - 1) / 2;
if (heap[index].val < heap[parent].val)
{
Swap(index, parent);
index = parent;
}
else
break;
}
}
private void HeapifyDown(int index)
{
int last = heap.Count - 1;
while (true)
{
int left = 2 * index + 1;
int right = 2 * index + 2;
int smallest = index;
if (left <= last && heap[left].val < heap[smallest].val)
smallest = left;
if (right <= last && heap[right].val < heap[smallest].val)
smallest = right;
if (smallest != index)
{
Swap(index, smallest);
index = smallest;
}
else break;
}
}
public void Add((int val, int arrIdx, int elemIdx) item)
{
heap.Add(item);
HeapifyUp(heap.Count - 1);
}
public (int val, int arrIdx, int elemIdx) Pop() {
var top = heap[0];
heap[0] = heap[heap.Count - 1];
heap.RemoveAt(heap.Count - 1);
HeapifyDown(0);
return top;
}
public int Count()
{
return heap.Count;
}
}
class GFG {
//Driver Code Ends
static List<int> mergeArrays(int[,] mat) {
int k = mat.GetLength(0);
int nCols = mat.GetLength(1);
List<int> output = new List<int>();
// Min-heap: {value, array index, element index}
MinHeap minHeap = new MinHeap();
// Push first element of each array
for (int i = 0; i < k; i++)
{
if (nCols > 0)
minHeap.Add((mat[i, 0], i, 0));
}
// Merge all elements
while (minHeap.Count() > 0)
{
var top = minHeap.Pop();
int val = top.val;
int i = top.arrIdx;
int j = top.elemIdx;
output.Add(val);
// Push next element from same array
if (j + 1 < nCols)
minHeap.Add((mat[i, j + 1], i, j + 1));
}
return output;
}
//Driver Code Starts
static void Main()
{
int[,] mat = new int[,]
{
{1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}
};
List<int> result = mergeArrays(mat);
foreach (int x in result)
Console.Write(x + " ");
Console.WriteLine();
}
}
//Driver Code Ends
JavaScript
//Driver Code Starts
// Custom Min-Heap Priority Queue
class MinHeap {
constructor() {
this.heap = [];
}
swap(i, j) {
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
}
heapifyUp(index) {
while (index > 0) {
let parent = Math.floor((index - 1) / 2);
if (this.heap[index][0] < this.heap[parent][0]) {
this.swap(index, parent);
index = parent;
} else break;
}
}
heapifyDown(index) {
let last = this.heap.length - 1;
while (true) {
let left = 2 * index + 1;
let right = 2 * index + 2;
let smallest = index;
if (left <= last && this.heap[left][0] < this.heap[smallest][0])
smallest = left;
if (right <= last && this.heap[right][0] < this.heap[smallest][0])
smallest = right;
if (smallest !== index) {
this.swap(index, smallest);
index = smallest;
} else break;
}
}
add(item) {
this.heap.push(item);
this.heapifyUp(this.heap.length - 1);
}
pop() {
const top = this.heap[0];
this.heap[0] = this.heap[this.heap.length - 1];
this.heap.pop();
this.heapifyDown(0);
return top;
}
size() {
return this.heap.length;
}
}
//Driver Code Ends
function mergeArrays(mat) {
let k = mat.length;
let output = [];
// Min-heap: [value, array index, element index]
const minHeap = new MinHeap();
// Push first element of each array
for (let i = 0; i < k; i++) {
if (mat[i].length > 0) {
minHeap.add([mat[i][0], i, 0]);
}
}
// Merge all elements
while (minHeap.size() > 0) {
let [val, i, j] = minHeap.pop();
output.push(val);
// Push next element from same array
if (j + 1 < mat[i].length) {
minHeap.add([mat[i][j + 1], i, j + 1]);
}
}
return output;
}
//Driver Code Starts
// Driver code
let mat = [
[1, 3, 5, 7],
[2, 4, 6, 8],
[0, 9, 10, 11]
];
let result = mergeArrays(mat);
console.log(result.join(' '));
//Driver Code Ends
Output0 1 2 3 4 5 6 7 8 9 10 11
Time Complexity: O(n*log(k)), k is number of rows and n is total number of elements.
Auxiliary Space: O(k)
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem