Merge two sorted arrays
Given two integer arrays a and b, each sorted in non-decreasing order,
return one array holding all their elements in non-decreasing order. Either array may be empty. Use O(m + n)
time.
Examples
| Input | Output | Why |
|---|---|---|
a = [1, 4, 7], b = [2, 3, 9] | [1, 2, 3, 4, 7, 9] | |
a = [], b = [1, 2] | [1, 2] | |
a = [2, 2, 2], b = [2, 2] | [2, 2, 2, 2, 2] | Equal values are all kept. |
Constraints
- 0 ≤ m, n ≤ 10⁴
- −10⁹ ≤ a[i], b[j] ≤ 10⁹
- a and b are sorted in non-decreasing order
Hints
Hint 1
Concatenating and sorting is O((m + n) log(m + n)). The inputs are already sorted; use that.
Hint 2
The smallest value overall is the smaller of a[0] and b[0]. What is the next smallest?
Hint 3
Keep a pointer into each array. Take the smaller of the two front values, advance that pointer, and repeat. When one array runs out, copy the rest of the other.
Where people lose marks
- Forgetting the tail: the loop ends when either array runs out, and the other may still hold values.
- Using a[i] < b[j] for the tie: the result is still sorted, but the merge is no longer stable.
Dry run on [2,5,8],[1,5,6,9]
Read it one frame at a time, the way you would trace the code on paper in an interview. Each frame shows the state after the step it describes.
-
Step 1 / 8a20i5182b10j516293out·0i0j0
One pointer at the front of each array.
-
Step 2 / 8a20i5182b1051j6293out10i0j1
2 > 1: take 1 from b.
-
Step 3 / 8a2051i82b1051j6293out1021i1j1
2 ≤ 5: take 2 from a.
-
Step 4 / 8a205182ib1051j6293out102152i2j1
5 ≤ 5: take 5 from a. On a tie a goes first, which keeps the merge stable.
-
Step 5 / 8a205182ib105162j93out10215253i2j2
8 > 5: take 5 from b.
-
Step 6 / 8a205182ib10516293jout1021525364i2j3
8 > 6: take 6 from b.
-
Step 7 / 8a205182b10516293jout102152536485i3j3
8 ≤ 9: take 8 from a.
-
Step 8 / 8a205182b10516293out10215253648596length7
One array is used up; the rest of b is already sorted and is appended as it is.
How to think about it
At every step the smallest value not yet output is at the front of one of the two arrays, because each
array is sorted. So keep i into a and j into b, append the
smaller of a[i] and b[j], and advance that pointer. When one array is exhausted, the
rest of the other is already in order and is appended as it is.
Taking from a on ties (a[i] ≤ b[j]) makes the merge stable: equal values keep
the order of their arrays, which is what merge sort relies on to be stable itself.
Complexity. Time O(m + n) · Space O(m + n) for the output
The solution, in six languages
Each one is compiled and run against the test table before it is published. Java is reviewed by hand.
def merge_sorted(a, b):
out = []
i = j = 0
while i < len(a) and j < len(b):
if a[i] <= b[j]: # ties from a keep the merge stable
out.append(a[i])
i += 1
else:
out.append(b[j])
j += 1
out.extend(a[i:]) # at most one of these is non-empty
out.extend(b[j:])
return out#include <vector>
std::vector<int> solve(const std::vector<int>& a, const std::vector<int>& b) {
std::vector<int> out;
out.reserve(a.size() + b.size());
size_t i = 0, j = 0;
while (i < a.size() && j < b.size()) out.push_back(a[i] <= b[j] ? a[i++] : b[j++]);
while (i < a.size()) out.push_back(a[i++]);
while (j < b.size()) out.push_back(b[j++]);
return out;
}class Solution {
public int[] mergeSorted(int[] a, int[] b) {
int[] out = new int[a.length + b.length];
int i = 0, j = 0, k = 0;
while (i < a.length && j < b.length) out[k++] = a[i] <= b[j] ? a[i++] : b[j++];
while (i < a.length) out[k++] = a[i++];
while (j < b.length) out[k++] = b[j++];
return out;
}
}function mergeSorted(a, b) {
const out = [];
let i = 0, j = 0;
while (i < a.length && j < b.length) out.push(a[i] <= b[j] ? a[i++] : b[j++]);
while (i < a.length) out.push(a[i++]);
while (j < b.length) out.push(b[j++]);
return out;
}fn solve(a: &[i64], b: &[i64]) -> Vec<i64> {
let mut out = Vec::with_capacity(a.len() + b.len());
let (mut i, mut j) = (0, 0);
while i < a.len() && j < b.len() {
if a[i] <= b[j] { out.push(a[i]); i += 1; } else { out.push(b[j]); j += 1; }
}
out.extend_from_slice(&a[i..]);
out.extend_from_slice(&b[j..]);
out
}solve :: [Int] -> [Int] -> [Int]
solve [] ys = ys
solve xs [] = xs
solve (x:xs) (y:ys)
| x <= y = x : solve xs (y:ys) -- ties from the first list keep it stable
| otherwise = y : solve (x:xs) ys
Variants to try
- Merge in place into a, which has room for n extra values at its end: fill from the back, comparing the largest values first.
- Merge k sorted arrays: a min-heap of the k front values, O(N log k) for N values in total.
Next problems
A palindrome, ignoring punctuation and case
Compare from both ends inward, stepping over anything that is not a letter or a digit. No cleaned copy of the string is needed.
Open the problem → Easy10 minMove the zeros to the end
One pointer reads every element, the other marks where the next non-zero belongs. The order of the non-zero values is kept.
Open the problem → Easy10 minPair with a given sum in a sorted array
The cleanest example of the two-pointer idea: sorted input, one pass, no extra memory.
Open the problem →Write a solution and run it against the real test table.
Keep going
A palindrome, ignoring punctuation and case
Compare from both ends inward, stepping over anything that is not a letter or a digit. No cleaned copy of the string is needed.
Open the problem → Easy10 minMove the zeros to the end
One pointer reads every element, the other marks where the next non-zero belongs. The order of the non-zero values is kept.
Open the problem → Easy10 minPair with a given sum in a sorted array
The cleanest example of the two-pointer idea: sorted input, one pass, no extra memory.
Open the problem → Two pointersThe pattern behind it
Two indices walking a sorted or paired structure, each step ruling out one candidate for good.
Read the pattern →Preparing for a real process? Quant interview preparation, or book a free 20-minute call.