A detailed guide to solving Merge Sorted Array in-place by merging from the back with three pointers.
Problem Restatement
We are given two integer arrays:
nums1
nums2Both arrays are sorted in non-decreasing order.
We are also given two integers:
m
nThe first m elements of nums1 are valid sorted elements.
The array nums2 contains n valid sorted elements.
The total length of nums1 is m + n, so it has enough space to hold all elements from both arrays.
We need to merge nums2 into nums1 in-place, so that nums1 becomes one sorted array.
The function should not return the final array. It should modify nums1 directly. The last n zeroes in nums1 are placeholders and should be ignored before merging.
Input and Output
| Item | Meaning |
|---|---|
| Input | nums1, m, nums2, n |
| Output | Nothing returned |
| Mutation | Store the merged sorted result inside nums1 |
Valid part of nums1 | First m elements |
Valid part of nums2 | All n elements |
| Placeholder part | Last n elements of nums1 |
Function shape:
class Solution:
def merge(self, nums1: list[int], m: int, nums2: list[int], n: int) -> None:
...Examples
Example 1:
nums1 = [1, 2, 3, 0, 0, 0]
m = 3
nums2 = [2, 5, 6]
n = 3The valid arrays are:
[1, 2, 3]
[2, 5, 6]After merging:
nums1 = [1, 2, 2, 3, 5, 6]Example 2:
nums1 = [1]
m = 1
nums2 = []
n = 0There is nothing to merge from nums2.
After merging:
nums1 = [1]Example 3:
nums1 = [0]
m = 0
nums2 = [1]
n = 1There are no valid elements in nums1.
The 0 is only placeholder space.
After merging:
nums1 = [1]First Thought: Use an Extra Array
A simple way is to copy the valid part of nums1 and all of nums2 into a new array, sort it, then copy it back.
merged = nums1[:m] + nums2
merged.sort()
nums1[:] = mergedThis works, but it does not use the sorted structure fully.
It also uses extra space.
We can do better by merging directly.
Key Insight
Both arrays are already sorted.
If we merge from the front, we may overwrite valid elements in nums1.
Example:
nums1 = [1, 2, 3, 0, 0, 0]
nums2 = [2, 5, 6]If we place 2 from nums2 near the front, we may overwrite 2 or 3 from the valid part of nums1.
But nums1 has empty space at the back.
So we merge from the back.
The largest remaining value among both arrays belongs at the last open position in nums1.
Use three pointers:
| Pointer | Starts at | Meaning |
|---|---|---|
i | m - 1 | Last valid element in nums1 |
j | n - 1 | Last element in nums2 |
write | m + n - 1 | Position to fill next in nums1 |
At every step, compare:
nums1[i]
nums2[j]Place the larger one at:
nums1[write]Then move the corresponding pointer left.
Algorithm
Initialize:
i = m - 1
j = n - 1
write = m + n - 1While j >= 0:
- If
i >= 0andnums1[i] > nums2[j], placenums1[i]atnums1[write]. - Otherwise, place
nums2[j]atnums1[write]. - Move the pointer that supplied the value.
- Move
writeleft.
We only need to loop while j >= 0.
If nums2 is fully copied, the remaining valid elements of nums1 are already in the correct place.
Walkthrough
Use:
nums1 = [1, 2, 3, 0, 0, 0]
m = 3
nums2 = [2, 5, 6]
n = 3Start:
i = 2 # nums1[i] = 3
j = 2 # nums2[j] = 6
write = 5Compare 3 and 6.
Place 6 at the end:
nums1 = [1, 2, 3, 0, 0, 6]
j = 1
write = 4Compare 3 and 5.
Place 5:
nums1 = [1, 2, 3, 0, 5, 6]
j = 0
write = 3Compare 3 and 2.
Place 3:
nums1 = [1, 2, 3, 3, 5, 6]
i = 1
write = 2Compare 2 and 2.
Since nums1[i] > nums2[j] is false, place nums2[j]:
nums1 = [1, 2, 2, 3, 5, 6]
j = -1
write = 1Now nums2 is fully copied.
Stop.
The final array is:
[1, 2, 2, 3, 5, 6]Correctness
The algorithm fills nums1 from right to left.
At each step, write points to the largest still-empty position in the final merged array.
The largest remaining value must be either the last unused valid value of nums1 or the last unused value of nums2, because both arrays are sorted.
So comparing nums1[i] and nums2[j] identifies the correct value for nums1[write].
After placing that value, the algorithm moves the corresponding pointer left. The suffix after write is now correct and will never be changed again.
This invariant holds after every step: all positions to the right of write contain the largest already-merged values in sorted order.
When nums2 has no remaining elements, every value from nums2 has been placed. Any remaining values from the original valid part of nums1 are already before write and already sorted. Therefore, the whole array is correctly merged.
Complexity
Let:
m = number of valid elements in nums1
n = number of elements in nums2| Metric | Value | Why |
|---|---|---|
| Time | O(m + n) | Each element is considered at most once |
| Space | O(1) | The merge uses only three pointers |
Implementation
class Solution:
def merge(self, nums1: list[int], m: int, nums2: list[int], n: int) -> None:
i = m - 1
j = n - 1
write = m + n - 1
while j >= 0:
if i >= 0 and nums1[i] > nums2[j]:
nums1[write] = nums1[i]
i -= 1
else:
nums1[write] = nums2[j]
j -= 1
write -= 1Code Explanation
Start at the end of the valid part of nums1:
i = m - 1Start at the end of nums2:
j = n - 1Start writing at the final position of nums1:
write = m + n - 1The loop continues until all values from nums2 are placed:
while j >= 0:If nums1 still has values and its current value is larger, use it:
if i >= 0 and nums1[i] > nums2[j]:
nums1[write] = nums1[i]
i -= 1Otherwise, use the current value from nums2:
else:
nums1[write] = nums2[j]
j -= 1Then move the write pointer left:
write -= 1No return statement is needed because LeetCode checks the mutation of nums1.
Testing
def check(nums1, m, nums2, n, expected):
s = Solution()
s.merge(nums1, m, nums2, n)
assert nums1 == expected
def run_tests():
check([1, 2, 3, 0, 0, 0], 3, [2, 5, 6], 3, [1, 2, 2, 3, 5, 6])
check([1], 1, [], 0, [1])
check([0], 0, [1], 1, [1])
check([2, 0], 1, [1], 1, [1, 2])
check([1, 2, 4, 0, 0, 0], 3, [2, 3, 5], 3, [1, 2, 2, 3, 4, 5])
check([-1, 0, 0, 3, 3, 3, 0, 0, 0], 6, [1, 2, 2], 3, [-1, 0, 0, 1, 2, 2, 3, 3, 3])
print("all tests passed")
run_tests()Test meaning:
| Test | Why |
|---|---|
[1, 2, 3] and [2, 5, 6] | Main example |
nums2 empty | Nothing to merge |
nums1 has no valid elements | Copy all of nums2 |
Smaller nums2 element | Confirms backward merge can overwrite placeholder correctly |
| Interleaved arrays | Checks normal merge behavior |
| Negative numbers and duplicates | Confirms sorted order with repeated values |