Merge Two Sorted Arrays without Extra Space

In this tutorial, we will write the Python program to merge the two sorted arrays without taking an extra array or space. This problem is commonly asked in the technical interview. We will solve this problem using the various techniques. Let's understand the problem statement.

We are given two lists, arr1, and arr2, both sorted in ascending order. We need to combine them into a single sorted list, without using any extra storage space. The arr1 holds the first N elements and arr2 contains the last M elements. In the end, both arr1 and arr2 will be sorted.

Let's understand the solutions.

Approach - 1: Brute-Force (Naïve Approach)

In the naive approach, we repeatedly compare and swap elements from both arrays to merge them into a single sorted list. Below is a Python implementation of the naive approach.

Example -

Output

arr1 after merge: [1, 2, 3, 4]
arr2 after merge: [6, 7, 8]

Explanation -

The above code demonstrates a naive approach to merge two sorted arrays `arr1` and arr2 into a single sorted array without using any extra space. Here's a step-by-step explanation:

  1. We define a function merge_sorted_arrays_naive that takes four arguments: arr1, arr2 (the second sorted array), n (the length of arr1), and m (the length of arr2).
  2. Inside the function, we use a nested loop to iterate through each element in arr1 (the outer loop) and the elements in arr2 (the inner loop).
  3. For each element in arr1, we compare it with the first element of arr2 (since both arrays are sorted). If an element in arr1 is greater than the first element of arr2, we swap them using the tuple unpacking feature in Python.
  4. After swapping, we sort `arr2` to maintain its sorted order, as swapping elements may disrupt the order.
  5. We repeat this process for each element in arr1, effectively merging the two arrays. This approach ensures that the merged arr1 contains the first n elements, and arr2 contains the last m elements.
  6. Finally, we return the modified `arr1` and `arr2`.
  7. In the example usage, we demonstrate how to use the merge_sorted_arrays_naive() function with two sample arrays, arr1 and arr2. After merging, we print the modified arrays.

It's important to note that this naive approach is not the most efficient method for merging sorted arrays, especially for large arrays, as it involves repeatedly sorting arr2. There are more efficient algorithms for merging two sorted arrays without extra space, such as the merge-sort based approach, which has a time complexity of O(n + m).

Optimal Approach - 1

This solution is more efficient than the brute-force approach. Let's understand the following example -

Example -

Output

arr1 after merging: [0, 1, 2, 3]
arr2 after merging: [5, 6, 7, 8, 9]

Explanation -

In the above code, we initialized the two pointers, left and right, where left points to the last index of arr1, and right points to the first index of arr2.

While left is greater than or equal to 0 and right is less than m (the length of arr2), we compare the elements at these pointers. If arr1[left] is greater than arr2[right], we swap the elements. Otherwise, we stop moving the pointers as the arrays are sorted.

After the pointers have traversed the arrays, arr1 will contain smaller elements, and arr2 will contain larger elements.

Finally, we sort both arr1 and arr2 to ensure they are sorted in ascending order.

Time Complexity: O(n * log(n) + m * log(m)) + O(n + m)

Space Complexity - 0(1) as we are not using the extra space.

Optimal Solution - 2

In this method, we will use the Gap method which is based on the shell sort algorithm. It is a technique used to merge two sorted arrays in-place efficiently. This method optimizes the naive approach by reducing the number of comparisons and swaps. Let's understand the following example.

Example -

Output

arr1 after merging: [0, 1, 2, 3]
arr2 after merging: [5, 6, 7, 8, 9]

Explanation -

In the above code:

We calculate the initial gap by summing the lengths of both arrays and dividing by 2.

We use a while loop that continues as long as the gap is greater than 0. This loop controls the sorting and merging process based on the gap value.

In the first part of the loop, we perform shell sort within arr1 and then compare and swap elements that are gap positions apart until the end of arr1 is reached.

In the second part, we merge elements between arr1 and arr2 and then compare and swap elements within the gap distance and advance the pointers i and j accordingly.

Finally, if elements in arr2 are left to be sorted (i.e., if j is less than m), we perform shell sort within arr2.

We reduce the gap by half in each iteration continuing the sorting process until the gap becomes 0.

This implementation efficiently merges the two sorted arrays without using extra space and is based on the Gap Method derived from Shell Sort. The time complexity of this method is better than the naive approach.

Conclusion

In this tutorial, we learned how to merge two sorted arrays without using extra space. We explored three approaches: a naive method involving sorting, an optimal approach using pointers, and an efficient method based on the Gap technique derived from Shell Sort. The optimal and efficient methods minimize unnecessary swaps and comparisons, making them more suitable for large arrays. By following these techniques, you can merge sorted arrays in-place, making it a valuable skill for technical interviews and real-world applications.