Efficiently merging two sorted arrays with O(1) extra space
Last Updated :
18 Sep, 2023
Given two sorted arrays, we need to merge them in O((n+m)*log(n+m)) time with O(1) extra space into a sorted array, when n is the size of the first array, and m is the size of the second array.
Example:
Input: ar1[] = {10};
ar2[] = {2, 3};
Output: ar1[] = {2}
ar2[] = {3, 10}
Input: ar1[] = {1, 5, 9, 10, 15, 20};
ar2[] = {2, 3, 8, 13};
Output: ar1[] = {1, 2, 3, 5, 8, 9}
ar2[] = {10, 13, 15, 20}
We have discussed a quadratic time solution in the below post.
In this post, a better solution is discussed.
Approach: The idea is that we start comparing elements that are far from each other rather than adjacent.
For every pass, we calculate the gap and compare the elements towards the right of the gap.
Every pass, the gap reduces to the ceiling value of dividing by 2.
Examples:
First example:
a1[] = {3 27 38 43},
a2[] = {9 10 82}
Start with
gap = ceiling of n/2 = 4
[This gap is for whole merged array]
3 27 38 43 9 10 82
3 27 38 43 9 10 82
3 10 38 43 9 27 82
gap = 2:
3 10 38 43 9 27 82
3 10 38 43 9 27 82
3 10 38 43 9 27 82
3 10 9 43 38 27 82
3 10 9 27 38 43 82
gap = 1:
3 10 9 27 38 43 82
3 10 9 27 38 43 82
3 9 10 27 38 43 82
3 9 10 27 38 43 82
3 9 10 27 38 43 82
3 9 10 27 38 43 82
Output : 3 9 10 27 38 43 82
Second Example:
a1[] = {10 27 38 43 82},
a2[] = {3 9}
Start with gap = ceiling of n/2 (4):
10 27 38 43 82 3 9
10 27 38 43 82 3 9
10 3 38 43 82 27 9
10 3 9 43 82 27 38
gap = 2:
10 3 9 43 82 27 38
9 3 10 43 82 27 38
9 3 10 43 82 27 38
9 3 10 43 82 27 38
9 3 10 27 82 43 38
9 3 10 27 38 43 82
gap = 1
9 3 10 27 38 43 82
3 9 10 27 38 43 82
3 9 10 27 38 43 82
3 9 10 27 38 43 82
3 9 10 27 38 43 82
3 9 10 27 38 43 82
Output : 3 9 10 27 38 43 82
Algorithm:
1. Define a function to find the next gap. This function takes the current gap as input, and returns the next gap to be used in the merge step.
2. Define a merge function that takes two sorted arrays arr1 and arr2, and their respective sizes n and m as inputs. This function will merge the two arrays into arr1.
3. Initialize a variable gap to n + m.
4. Repeat the following steps while gap is greater than 0:
a. Calculate the next gap using the nextGap function.
b. Compare and swap adjacent elements in the first array arr1, up to the index (n – 1), with a gap of the calculated next gap.
c. Compare and swap elements in both arrays arr1 and arr2, starting at index i and j respectively, with a gap of the calculated next gap, until i is less than n and j is less than m.
d. If j is less than m, compare and swap adjacent elements in the second array arr2, up to the index (m – 1), with a gap of the calculated next gap.
5. Output the sorted array arr1 and arr2.
Below is the implementation of the above idea:
C++
Java
Python3
def nextGap(gap):
if (gap < = 1 ):
return 0
return (gap / / 2 ) + (gap % 2 )
def merge(arr1, arr2, n, m):
gap = n + m
gap = nextGap(gap)
while gap > 0 :
i = 0
while i + gap < n:
if (arr1[i] > arr1[i + gap]):
arr1[i], arr1[i + gap] = arr1[i + gap], arr1[i]
i + = 1
j = gap - n if gap > n else 0
while i < n and j < m:
if (arr1[i] > arr2[j]):
arr1[i], arr2[j] = arr2[j], arr1[i]
i + = 1
j + = 1
if (j < m):
j = 0
while j + gap < m:
if (arr2[j] > arr2[j + gap]):
arr2[j], arr2[j + gap] = arr2[j + gap], arr2[j]
j + = 1
gap = nextGap(gap)
if __name__ = = "__main__" :
a1 = [ 10 , 27 , 38 , 43 , 82 ]
a2 = [ 3 , 9 ]
n = len (a1)
m = len (a2)
merge(a1, a2, n, m)
print ( "First Array: " , end = "")
for i in range (n):
print (a1[i], end = " " )
print ()
print ( "Second Array: " , end = "")
for i in range (m):
print (a2[i], end = " " )
print ()
|
C#
using System;
class GFG {
static int nextGap( int gap)
{
if (gap <= 1)
return 0;
return (gap / 2) + (gap % 2);
}
private static void merge( int [] arr1, int [] arr2, int n,
int m)
{
int i, j, gap = n + m;
for (gap = nextGap(gap); gap > 0;
gap = nextGap(gap))
{
for (i = 0; i + gap < n; i++)
if (arr1[i] > arr1[i + gap])
{
int temp = arr1[i];
arr1[i] = arr1[i + gap];
arr1[i + gap] = temp;
}
for (j = gap > n ? gap - n : 0; i < n && j < m;
i++, j++)
if (arr1[i] > arr2[j])
{
int temp = arr1[i];
arr1[i] = arr2[j];
arr2[j] = temp;
}
if (j < m) {
for (j = 0; j + gap < m; j++)
if (arr2[j] > arr2[j + gap])
{
int temp = arr2[j];
arr2[j] = arr2[j + gap];
arr2[j + gap] = temp;
}
}
}
}
public static void Main()
{
int [] a1 = { 10, 27, 38, 43, 82 };
int [] a2 = { 3, 9 };
merge(a1, a2, a1.Length, a2.Length);
Console.Write( "First Array: " );
for ( int i = 0; i < a1.Length; i++) {
Console.Write(a1[i] + " " );
}
Console.WriteLine();
Console.Write( "Second Array: " );
for ( int i = 0; i < a2.Length; i++) {
Console.Write(a2[i] + " " );
}
}
}
|
PHP
<?php
function nextGap( $gap )
{
if ( $gap <= 1)
return 0;
return ( $gap / 2) +
( $gap % 2);
}
function merge( $arr1 , $arr2 ,
$n , $m )
{
$i ;
$j ;
$gap = $n + $m ;
for ( $gap = nextGap( $gap );
$gap > 0; $gap = nextGap( $gap ))
{
for ( $i = 0; $i + $gap < $n ; $i ++)
if ( $arr1 [ $i ] > $arr1 [ $i + $gap ])
{
$tmp = $arr1 [ $i ];
$arr1 [ $i ] = $arr1 [ $i + $gap ];
$arr1 [ $i + $gap ] = $tmp ;
}
for ( $j = $gap > $n ? $gap - $n : 0 ;
$i < $n && $j < $m ; $i ++, $j ++)
if ( $arr1 [ $i ] > $arr2 [ $j ])
{
$tmp = $arr1 [ $i ];
$arr1 [ $i ] = $arr2 [ $j ];
$arr2 [ $j ] = $tmp ;
}
if ( $j < $m )
{
for ( $j = 0; $j + $gap < $m ; $j ++)
if ( $arr2 [ $j ] > $arr2 [ $j + $gap ])
{
$tmp = $arr2 [ $j ];
$arr2 [ $j ] = $arr2 [ $j + $gap ];
$arr2 [ $j + $gap ] = $tmp ;
}
}
}
echo "First Array: " ;
for ( $i = 0; $i < $n ; $i ++)
echo $arr1 [ $i ]. " " ;
echo "\nSecond Array: " ;
for ( $i = 0; $i < $m ; $i ++)
echo $arr2 [ $i ] . " " ;
echo "\n" ;
}
$a1 = array (10, 27, 38, 43 ,82);
$a2 = array (3,9);
$n = sizeof( $a1 );
$m = sizeof( $a2 );
merge( $a1 , $a2 , $n , $m );
?>
|
Javascript
<script>
function nextGap(gap)
{
if (gap <= 1)
return 0;
return parseInt(gap / 2, 10) + (gap % 2);
}
function merge(arr1, arr2, n, m)
{
let i, j, gap = n + m;
for (gap = nextGap(gap); gap > 0;
gap = nextGap(gap))
{
for (i = 0; i + gap < n; i++)
if (arr1[i] > arr1[i + gap])
{
let temp = arr1[i];
arr1[i] = arr1[i + gap];
arr1[i + gap] = temp;
}
for (j = gap > n ? gap - n : 0; i < n && j < m;
i++, j++)
if (arr1[i] > arr2[j])
{
let temp = arr1[i];
arr1[i] = arr2[j];
arr2[j] = temp;
}
if (j < m) {
for (j = 0; j + gap < m; j++)
if (arr2[j] > arr2[j + gap])
{
let temp = arr2[j];
arr2[j] = arr2[j + gap];
arr2[j + gap] = temp;
}
}
}
}
let a1 = [ 10, 27, 38, 43, 82 ];
let a2 = [ 3, 9 ];
merge(a1, a2, a1.length, a2.length);
document.write( "First Array: " );
for (let i = 0; i < a1.length; i++) {
document.write(a1[i] + " " );
}
document.write( "</br>" );
document.write( "Second Array: " );
for (let i = 0; i < a2.length; i++) {
document.write(a2[i] + " " );
}
</script>
|
Output
First Array: 3 9 10 27 38
Second Array: 43 82
Time Complexity: O(n + m), as the gap is considered to be n+m.
Auxiliary Space: O(1)
Another method in O(m+n) time complexity:
Here we use the below technique:
Suppose we have a number A and we want to
convert it to a number B and there is also a
constraint that we can recover number A any
time without using other variable.To achieve
this we choose a number N which is greater
than both numbers and add B*N in A.
so A --> A+B*N
To get number B out of (A+B*N)
we divide (A+B*N) by N.
so (A+B*N)/N = B.
To get number A out of (A+B*N)
we take modulo with N.
so (A+B*N)%N = A.
-> In short by taking modulo
we get old number back and taking divide
we new number.
We first find the maximum element of both arrays and increment it by one to avoid collision of 0 and maximum element during modulo operation. The idea is to traverse both arrays from starting simultaneously. Let’s say an element in a is a[i] and in b is b[j] and k is the position at where the next minimum number will come. Now update value a[k] if k<n else b[k-n] by adding min(a[i],b[j])*maximum_element. After updating all the elements divide all the elements by maximum_element so we get the updated array back.
Below is the implementation of the above idea:
C++
#include <bits/stdc++.h>
using namespace std;
void mergeArray( int a[], int b[], int n, int m)
{
int mx = 0;
for ( int i = 0; i < n; i++) {
mx = max(mx, a[i]);
}
for ( int i = 0; i < m; i++) {
mx = max(mx, b[i]);
}
mx++;
int i = 0, j = 0, k = 0;
while (i < n && j < m && k < (n + m)) {
int e1 = a[i] % mx;
int e2 = b[j] % mx;
if (e1 <= e2) {
if (k < n)
a[k] += (e1 * mx);
else
b[k - n] += (e1 * mx);
i++;
k++;
}
else {
if (k < n)
a[k] += (e2 * mx);
else
b[k - n] += (e2 * mx);
j++;
k++;
}
}
while (i < n) {
int el = a[i] % mx;
if (k < n)
a[k] += (el * mx);
else
b[k - n] += (el * mx);
i++;
k++;
}
while (j < m) {
int el = b[j] % mx;
if (k < n)
a[k] += (el * mx);
else
b[k - n] += (el * mx);
j++;
k++;
}
for ( int i = 0; i < n; i++)
a[i] = a[i] / mx;
for ( int i = 0; i < m; i++)
b[i] = b[i] / mx;
return ;
}
int main()
{
int a[] = { 3, 5, 6, 8, 12 };
int b[] = { 1, 4, 9, 13 };
int n = sizeof (a) / sizeof ( int );
int m = sizeof (b) / sizeof ( int );
mergeArray(a, b, n, m);
cout << "First array : " ;
for ( int i = 0; i < n; i++)
cout << a[i] << " " ;
cout << endl;
cout << "Second array : " ;
for ( int i = 0; i < m; i++)
cout << b[i] << " " ;
cout << endl;
return 0;
}
|
Java
import java.io.*;
class GFG{
static void mergeArray( int a[], int b[],
int n, int m)
{
int mx = 0 ;
for ( int i = 0 ; i < n; i++)
{
mx = Math.max(mx, a[i]);
}
for ( int i = 0 ; i < m; i++)
{
mx = Math.max(mx, b[i]);
}
mx++;
int i = 0 , j = 0 , k = 0 ;
while (i < n && j < m && k < (n + m))
{
int e1 = a[i] % mx;
int e2 = b[j] % mx;
if (e1 <= e2)
{
if (k < n)
a[k] += (e1 * mx);
else
b[k - n] += (e1 * mx);
i++;
k++;
}
else
{
if (k < n)
a[k] += (e2 * mx);
else
b[k - n] += (e2 * mx);
j++;
k++;
}
}
while (i < n)
{
int el = a[i] % mx;
if (k < n)
a[k] += (el * mx);
else
b[k - n] += (el * mx);
i++;
k++;
}
while (j < m)
{
int el = b[j] % mx;
if (k < n)
b[k] += (el * mx);
else
b[k - n] += (el * mx);
j++;
k++;
}
for ( int in = 0 ; in < n; in++)
a[in] = a[in] / mx;
for ( int in = 0 ; in < m; in++)
b[in] = b[in] / mx;
return ;
}
public static void main(String[] args)
{
int a[] = { 3 , 5 , 6 , 8 , 12 };
int b[] = { 1 , 4 , 9 , 13 };
int n = a.length;
int m = b.length;
mergeArray(a, b, n, m);
System.out.print( "First array : " );
for ( int i = 0 ; i < n; i++)
System.out.print(a[i] + " " );
System.out.println();
System.out.print( "Second array : " );
for ( int i = 0 ; i < m; i++)
System.out.print(b[i] + " " );
System.out.println();
}
}
|
Python3
def mergeArray(a, b, n, m):
mx = 0
for i in range (n):
mx = max (mx, a[i])
for i in range (m):
mx = max (mx, b[i])
mx + = 1
i = 0
j = 0
k = 0
while (i < n & j < m & k < (n + m)):
e1 = (a[i] % mx)
e2 = (b[j] % mx)
if (e1 < = e2):
if (k < n):
a[k] + = (e1 * mx)
else :
b[k - n] + = (e1 * mx)
i + = 1
k + = 1
else :
if (k < n):
a[k] + = (e2 * mx)
else :
b[k - n] + = (e2 * mx)
j + = 1 ;
k + = 1 ;
while (i < n):
el = (a[i] % mx)
if (k < n):
a[k] + = (el * mx)
else :
b[k - n] + = (el * mx)
i + = 1 ;
k + = 1 ;
while (j < m):
el = (b[j] % mx)
if (k < n):
a[k] + = (el * mx)
else :
b[k - n] + = (el * mx)
j + = 1 ;
k + = 1 ;
for In in range (n):
a[In] = int ( float (a[In]) / float (mx))
for In in range (m):
b[In] = int ( float (b[In]) / float (mx))
return
if __name__ = = "__main__" :
a = [ 3 , 5 , 6 , 8 , 12 ]
b = [ 1 , 4 , 9 , 13 ]
n = len (a)
m = len (b)
mergeArray(a, b, n, m)
print ( "First Array: " , end = "")
for i in range (n):
print (a[i], end = " " )
print ()
print ( "Second Array: " , end = "")
for i in range (m):
print (b[i], end = " " )
print ()
|
C#
using System;
public class GFG{
static void mergeArray( int [] a, int [] b,
int n, int m)
{
int mx = 0;
for ( int I = 0; I < n; I++)
{
mx = Math.Max(mx, a[I]);
}
for ( int I = 0; I < m; I++)
{
mx = Math.Max(mx, b[I]);
}
mx++;
int i = 0, j = 0, k = 0;
while (i < n && j < m && k < (n + m))
{
int e1 = a[i] % mx;
int e2 = b[j] % mx;
if (e1 <= e2)
{
if (k < n)
a[k] += (e1 * mx);
else
b[k - n] += (e1 * mx);
i++;
k++;
}
else
{
if (k < n)
a[k] += (e2 * mx);
else
b[k - n] += (e2 * mx);
j++;
k++;
}
}
while (i < n)
{
int el = a[i] % mx;
if (k < n)
a[k] += (el * mx);
else
b[k - n] += (el * mx);
i++;
k++;
}
while (j < m)
{
int el = b[j] % mx;
if (k < n)
b[k] += (el * mx);
else
b[k - n] += (el * mx);
j++;
k++;
}
for ( int In = 0; In < n; In++)
a[In] = a[In] / mx;
for ( int In = 0; In < m; In++)
b[In] = b[In] / mx;
return ;
}
static public void Main (){
int [] a = { 3, 5, 6, 8, 12 };
int [] b = { 1, 4, 9, 13 };
int n = a.Length;
int m = b.Length;
mergeArray(a, b, n, m);
Console.Write( "First array : " );
for ( int i = 0; i < n; i++)
Console.Write(a[i] + " " );
Console.WriteLine();
Console.Write( "Second array : " );
for ( int i = 0; i < m; i++)
Console.Write(b[i] + " " );
Console.WriteLine();
}
}
|
Javascript
<script>
function mergeArray(a, b, n, m)
{
let mx = 0;
for (let i = 0; i < n; i++)
{
mx = Math.max(mx, a[i]);
}
for (let i = 0; i < m; i++)
{
mx = Math.max(mx, b[i]);
}
mx++;
let i = 0, j = 0, k = 0;
while (i < n && j < m && k < (n + m))
{
let e1 = a[i] % mx;
let e2 = b[j] % mx;
if (e1 <= e2)
{
if (k < n)
a[k] += (e1 * mx);
else
b[k - n] += (e1 * mx);
i++;
k++;
}
else
{
if (k < n)
a[k] += (e2 * mx);
else
b[k - n] += (e2 * mx);
j++;
k++;
}
}
while (i < n)
{
let el = a[i] % mx;
if (k < n)
a[k] += (el * mx);
else
b[k - n] += (el * mx);
i++;
k++;
}
while (j < m)
{
let el = b[j] % mx;
if (k < n)
a[k] += (el * mx);
else
b[k - n] += (el * mx);
j++;
k++;
}
for (let i = 0; i < n; i++)
a[i] = parseInt(a[i] / mx);
for (let i = 0; i < m; i++)
b[i] = parseInt(b[i] / mx);
return ;
}
var a = [ 3, 5, 6, 8, 12 ];
var b = [ 1, 4, 9, 13 ];
var n = a.length;
var m = b.length;
mergeArray(a, b, n, m);
document.write( "First array : " );
for (let i = 0; i < n; i++)
document.write(a[i] + " " );
document.write( '<br>' )
document.write( "Second array : " );
for (let i = 0; i < m; i++)
document.write(b[i] + " " );
</script>
|
Output
First array : 1 3 4 5 6
Second array : 8 9 12 13
Time Complexity: O(m+n)
The space complexity of the given program is O(n+m), where n and m are the lengths of the input arrays a and b, respectively. This is because two additional arrays of size n and m are created to store the merged elements, and no additional space is used apart from that. The input arrays are modified in place, so they do not contribute to the space complexity.
We have discussed a simple and efficient solution in the below post.
In this post, a better and simple solution is discussed.
The idea is: We will traverse the first array and compare it with the first element of the second array. If the first element of the second array is smaller than the first array, we will swap and then sort the second array.
- First, we have to traverse array1 and then compare it with the first element of array2.
If it is less than array1 then we swap both.
- After swapping we are going to sort the array2 again so that the smallest element of the array2
comes at the first position and we can again swap with the array1
- To sort the array2 we will store the first element of array2 in a variable and left shift all the elements and store
the first element in array2 in the last.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
void mergeArray( int arr1[], int arr2[],
int n, int m)
{
for ( int i = 0; i < n; i++)
{
if (arr1[i] > arr2[0])
{
int temp = arr1[i];
arr1[i] = arr2[0];
arr2[0] = temp;
int firstElement = arr2[0];
int k;
for (k = 1;
k < m && arr2[k] < firstElement;
k++)
{
arr2[k - 1] = arr2[k];
}
arr2[k - 1] = firstElement;
}
}
for ( int i = 0; i < n; i++)
{
cout << arr1[i] << " " ;
}
cout << endl;
for ( int i = 0; i < m; i++)
{
cout << arr2[i] << " " ;
}
}
int main()
{
int arr1[] = { 1, 3, 5, 7 };
int arr2[] = { 0, 2, 6, 8, 9 };
int n = sizeof (arr1)/ sizeof (arr1[0]), m = sizeof (arr2)/ sizeof (arr2[0]);
mergeArray(arr1, arr2, n, m);
}
|
Java
import java.io.*;
class GFG {
public static void mergeArray( int [] arr1, int [] arr2)
{
int n = arr1.length;
int m = arr2.length;
for ( int i = 0 ; i < n; i++) {
if (arr1[i] > arr2[ 0 ]) {
int temp = arr1[i];
arr1[i] = arr2[ 0 ];
arr2[ 0 ] = temp;
int firstElement = arr2[ 0 ];
int k;
for (k = 1 ;
k < m && arr2[k] < firstElement;
k++)
{
arr2[k - 1 ] = arr2[k];
}
arr2[k - 1 ] = firstElement;
}
}
for ( int i : arr1) {
System.out.print(i + " " );
}
System.out.println();
for ( int i : arr2) {
System.out.print(i + " " );
}
}
public static void main(String[] args)
{
int [] arr1 = { 1 , 3 , 5 , 7 };
int [] arr2 = { 0 , 2 , 6 , 8 , 9 };
mergeArray(arr1, arr2);
}
}
|
Python3
def mergeArray(arr1, arr2):
n = len (arr1);
m = len (arr2);
for i in range (n):
if (arr1[i] > arr2[ 0 ]):
temp = arr1[i];
arr1[i] = arr2[ 0 ];
arr2[ 0 ] = temp;
firstElement = arr2[ 0 ];
k = 1 ;
for p in range ( 1 , m):
if (arr2[k] < firstElement):
arr2[k - 1 ] = arr2[k];
k + = 1 ;
arr2[k - 1 ] = firstElement;
print (arr1);
print (arr2);
if __name__ = = '__main__' :
arr1 = [ 1 , 3 , 5 , 7 ];
arr2 = [ 0 , 2 , 6 , 8 , 9 ];
mergeArray(arr1, arr2);
|
C#
using System;
class GFG{
public static void mergeArray( int [] arr1,
int [] arr2)
{
int n = arr1.Length;
int m = arr2.Length;
for ( int i = 0; i < n; i++)
{
if (arr1[i] > arr2[0])
{
int temp = arr1[i];
arr1[i] = arr2[0];
arr2[0] = temp;
int firstElement = arr2[0];
int k;
for (k = 1;
k < m && arr2[k] < firstElement;
k++)
{
arr2[k - 1] = arr2[k];
}
arr2[k - 1] = firstElement;
}
}
foreach ( int i in arr1)
{
Console.Write(i + " " );
}
Console.WriteLine();
foreach ( int i in arr2)
{
Console.Write(i + " " );
}
}
static public void Main()
{
int [] arr1 = { 1, 3, 5, 7 };
int [] arr2 = { 0, 2, 6, 8, 9 };
mergeArray(arr1, arr2);
}
}
|
Javascript
<script>
function mergeArray(arr1, arr2,
n, m)
{
for (let i = 0; i < n; i++)
{
if (arr1[i] > arr2[0])
{
let temp = arr1[i];
arr1[i] = arr2[0];
arr2[0] = temp;
let firstElement = arr2[0];
let k;
for (k = 1;
k < m && arr2[k] < firstElement;
k++)
{
arr2[k - 1] = arr2[k];
}
arr2[k - 1] = firstElement;
}
}
for (let i = 0; i < n; i++)
{
document.write(arr1[i] + " " );
}
document.write( "<br>" );
for (let i = 0; i < m; i++)
{
document.write(arr2[i] + " " );
}
}
let arr1 = [ 1, 3, 5, 7 ];
let arr2 = [ 0, 2, 6, 8, 9 ];
let n = 4, m = 5;
mergeArray(arr1, arr2, n, m);
</script>
|
Time Complexity: O(n*m)
Space Complexity: O(1)
Share your thoughts in the comments
Please Login to comment...