Merge Sorted Array problem in DSA: Brute Force, Merge Copy, and the Three-Pointer Trick

  • Last Updated: July 20, 2026
  • By: javahandson
  • Series
img

Merge Sorted Array problem in DSA: Brute Force, Merge Copy, and the Three-Pointer Trick

Learn the Merge Sorted Array problem in DSA the beginner-friendly way. We compare brute force, a copy merge, and the in-place three-pointer trick, with dry runs for all three and ten interview questions at the end. As a developer I will be using Java code but pseudo-codes, explanation and dry runs are language neutral and you can understand the concept easily. So don’t skip it because language is just a syntax.

1. Introduction

The Merge Sorted Array problem in DSA is one of those questions that looks easy, then trips you up on the details. You get two sorted arrays and you have to blend them into one. The twist is where the answer must live, and that small rule changes everything.

Here is the task in plain words. Somebody hands you two arrays that are already sorted. The first one carries extra empty space at the end, just enough to hold the second array. Your job is to pour the second array into the first and keep the whole thing sorted.

That spare tail is not an accident. It is a hint, and the best solution treats it as free workspace rather than as clutter to sort around.

We go slow here. First we try the blunt way, which is to dump everything in and sort. Then we merge into a fresh copy like a careful librarian. Finally we reach the three-pointer trick that fills the array from the back and needs no extra space at all.

1.1 What This Article Covers

Here is the road map for the rest of the guide.

  • A plain statement of the problem, plus the detail about those trailing zeros.
  • Three small ideas, sorted inputs, filling from the back, and why the front breaks.
  • Three approaches, each with pseudocode, code, a dry run, and its real cost.
  • A side-by-side table, and a short guide on which one to reach for.
  • Two follow-up questions interviewers like to bolt on afterwards.
  • The mistakes that cost people offers, and a small program that ties it together.
  • Ten interview questions with short, quotable answers.

2. Understanding the Problem

Let us pin down the rules first. This problem hides a few traps, and a clear statement keeps you safe.

2.1 The Rules in Plain Words

Every version of this question comes down to the same five rules.

  • You receive two arrays, both sorted in non-decreasing order.
  • The first array has room for m plus n values. Its first m slots hold real data, and the last n slots are placeholders.
  • The second array holds n real values.
  • Merge the second array into the first so the first ends up fully sorted.
  • The change happens in place, so nothing gets returned.

Worth knowing about the original version of this question: both m and n stay under a few hundred, and values range across roughly a billion in either direction. So the arrays are small. That means the interviewer is not testing raw speed here, they are testing whether you spot the free space.

2.2 A First Example

Take the first array as [1, 2, 3, 0, 0, 0] with m equal to 3, and the second as [2, 5, 6] with n equal to 3. After merging, the first array should read [1, 2, 2, 3, 5, 6].

Notice the two 2s sitting side by side. One came from each array, and duplicates are perfectly legal. Nothing gets removed here, so the final length is always m plus n.

Count the slots as a sanity check. Three real values plus three more equals six, which is exactly the length of the first array. That is never a coincidence, and it is the promise the spare tail is making.

2.3 Why the Trailing Zeros Matter

Those trailing zeros catch out almost everybody the first time. They look like data, and they are not.

Read them as empty parking bays. A zero in the tail means “nothing here yet”, so sorting it as a real value would drag a fake 0 into the middle of your answer. On our example that mistake produces [0, 0, 0, 1, 2, 3] plus the second array, which is nonsense.

This is why the count m exists as a separate argument. Without it you could not tell a real 0 in the data from a placeholder 0 in the tail. Trust m, never the zeros.

💡 Interview Insight
Interviewers love the in-place twist here. Say you would build a brand new array, and they will nudge you toward the empty tail of the first array instead. Naming that free space early shows you actually read the constraints.

3. Concepts You Need Here

Before the code, let us name the ideas that carry this problem. Each one is small, and you will reuse them in many array questions.

3.1 Two Sorted Inputs

Both arrays arrive already sorted. That is a gift, and throwing it away is the main sin of the brute force.

When two lists are sorted, you can walk them side by side and always know which candidate is next. Compare the two front values, take the smaller, and step that side forward. Repeat.

Think of two queues merging into one door. You never look further back than the person at the head of each queue, because nobody behind them can be shorter than they are.

3.2 Filling From the Back

The empty room sits at the end of the first array. So the safest place to write is the back, not the front.

Flip the comparison around and it works just as well. Instead of repeatedly taking the smallest remaining value and placing it at the front, take the largest remaining value and place it at the back. Both orders produce the same sorted result.

That single change is the heart of the best solution. Same merge, opposite direction, and suddenly no extra array is needed.

3.3 Why Filling From the Front Breaks

Now the detail that makes all of this click. Suppose you merge from the front, writing directly into the first array with no copy.

Take [1, 2, 3, 0, 0, 0] and [2, 5, 6] again. The very first comparison picks 1, which happily lands in slot 0. The second comparison picks a 2, and here comes the problem: writing it into slot 1 destroys the 2 that was already living there, and we still needed to read it.

So a front-to-back merge must protect the originals first, which is exactly why the copy approach exists. Every write lands on a slot whose value has not been used yet.

Filling from the back has no such problem, and here is the reason.

  • The write position starts at the last slot, which is a placeholder nobody needs.
  • Each step consumes one value and writes one value, so the write position moves left exactly as fast as the readers do.
  • The write position therefore stays at or behind the reader in the first array, never ahead of it.
  • Any slot we overwrite has already been read, so nothing gets destroyed.

4. Approach 1: Brute Force (Dump and Sort)

The first idea most people reach for is blunt but honest. Copy every value from the second array into the empty tail of the first. Then sort the whole thing and call it done.

4.1 Pseudocode

for j from 0 to n-1:
    nums1[m + j] = nums2[j]   // fill the empty tail
sort(nums1)                   // let the library sort it

Let us read that one line at a time, in plain words.

  • Line 1: the counter walks through the second array from its first value to its last, so it takes the values 0, 1, then 2 for a second array of size 3.
  • Line 2: each value gets copied into the first array at position m plus the counter. The first m slots already hold real data, so the empty room starts at m. That is why we add it. A counter of 0 writes to slot m, a counter of 1 writes to slot m plus 1, and so on down the tail.
  • Line 3: after the loop every value sits inside the first array, but the order is a mess. One sort call reorders the whole thing from smallest to largest.

So the plan is simple. First we pour the second array into the empty slots, then we let the sort clean up. It is short, and it is hard to get wrong.

4.2 Java Code

import java.util.Arrays;

public class MergeSortedArrayBrute {
    public static void merge(int[] nums1, int m,
                             int[] nums2, int n) {
        for (int j = 0; j < n; j++) {
            nums1[m + j] = nums2[j];
        }
        Arrays.sort(nums1);
    }

    public static void main(String[] args) {
        int[] nums1 = { 1, 2, 3, 0, 0, 0 };
        int[] nums2 = { 2, 5, 6 };
        merge(nums1, 3, nums2, 3);
        System.out.println(Arrays.toString(nums1));
        // Output: [1, 2, 2, 3, 5, 6]
    }
}

4.3 Why This Works, Step by Step

Let us read the logic slowly. Each part does one small job.

  • The loop copies the second array into the tail of the first, filling those placeholder slots.
  • After the loop, every value lives in one array, though the order is messy.
  • A single sort call then reorders the whole array from small to large.
  • Because the first array already has the right length, we sort it directly with no extra allocation.

This version is easy to read, and it always gives the correct answer. That is its strength. Its weakness is that it throws away the fact that both inputs arrived already sorted.

4.4 Dry Run of the Brute Force

Let us trace it with [1, 2, 3, 0, 0, 0], m equal to 3, and [2, 5, 6], n equal to 3. The empty slots sit at positions 3, 4, and 5. We copy first, then we sort.

Step Action First array after step
1 Copy 2 into slot 3 [1, 2, 3, 2, 0, 0]
2 Copy 5 into slot 4 [1, 2, 3, 2, 5, 0]
3 Copy 6 into slot 5 [1, 2, 3, 2, 5, 6]
4 Loop ends, the sort reorders everything [1, 2, 2, 3, 5, 6]

Let us narrate the trace, so nothing feels like magic.

  • Step 1: we grab the first value of the second array, which is 2, and write it at slot 3. The first placeholder is now a real value.
  • Step 2: the 5 goes into slot 4, and another placeholder disappears.
  • Step 3: the 6 goes into slot 5. Now every slot holds a value, and the array reads [1, 2, 3, 2, 5, 6].
  • Step 4: look at that array closely. The 2 from the second array is stuck between a 3 and a 5, out of order. Sorting slides everything into place.

So the stray 2 is the whole reason we need the sort. Copying alone does not keep things ordered. That sort works, yet it redoes effort, because both inputs were already sorted before we started.

4.5 Time and Space Cost

The copy loop takes O(n) time. Sorting takes O((m + n) log (m + n)) time, which dominates everything else, so that is the overall cost.

Space stays at O(1) beyond the array itself, because the sort runs in place. Memory is not the problem here.

On small inputs this is genuinely fine, and nobody will notice the difference. On larger ones that log factor is pure waste, since the sorted order we needed was handed to us for free.

5. Approach 2: Merge Into a Copy

Here is a smarter middle ground. Both arrays are sorted, so let us actually use that. We keep a copy of the first m values, then merge that copy with the second array, writing results into the first array from the front.

5.1 Pseudocode

copy = first m values of nums1
i = 0   // read pointer in copy
j = 0   // read pointer in nums2
k = 0   // write pointer in nums1
while i < m and j < n:
    if copy[i] <= nums2[j]:
        nums1[k] = copy[i]; k = k + 1; i = i + 1
    else:
        nums1[k] = nums2[j]; k = k + 1; j = j + 1
copy any leftover from copy or nums2

This one has more moving parts, so let us unpack it.

  • Line 1: we take a snapshot of the first m real values. That backup means we can overwrite the original freely without losing anything.
  • Lines 2 to 4: three pointers all start at 0. One reads the copy, one reads the second array, and one marks the next slot to write. Writing from the front is safe now, precisely because the copy keeps the originals out of harm’s way.
  • Line 5: the loop runs while both sides still hold values. The moment either side empties, it stops.
  • Lines 6 to 9: we compare the two front values. A smaller or equal value from the copy wins, otherwise the second array wins. Either way the write pointer advances too.
  • Line 10: once one side empties, the other still holds sorted values. We pour those straight in, no comparison needed.

Here is the key idea. Since both lists are sorted, the smaller front value is always the next one to place. So one clean sweep is enough.

5.2 Java Code

import java.util.Arrays;

public class MergeSortedArrayCopy {
    public static void merge(int[] nums1, int m,
                             int[] nums2, int n) {
        int[] copy = Arrays.copyOf(nums1, m);
        int i = 0, j = 0, k = 0;
        while (i < m && j < n) {
            if (copy[i] <= nums2[j]) {
                nums1[k++] = copy[i++];
            } else {
                nums1[k++] = nums2[j++];
            }
        }
        while (i < m) nums1[k++] = copy[i++];
        while (j < n) nums1[k++] = nums2[j++];
    }

    public static void main(String[] args) {
        int[] nums1 = { 1, 2, 3, 0, 0, 0 };
        int[] nums2 = { 2, 5, 6 };
        merge(nums1, 3, nums2, 3);
        System.out.println(Arrays.toString(nums1));
        // Output: [1, 2, 2, 3, 5, 6]
    }
}

5.3 Reading the Code Line by Line

Now let us map each part to what it actually does.

  • The first line builds a fresh array holding just the first m values. That is our safe backup.
  • Three pointers then start at the front. One reads the backup, one reads the second array, and one writes into the destination.
  • Our main loop runs while both sides still have values. The moment either pointer runs past its end, the loop stops.
  • The comparison checks which front value is smaller. On a tie we take from the backup, which keeps equal values in a stable order.
  • Writing a value also advances both the write pointer and whichever read pointer supplied it.
  • Two trailing loops handle leftovers. One drains the backup, the other drains the second array, and only one of them ever runs.

That stability detail is worth a sentence. Taking from the backup on a tie means values originally in the first array stay ahead of equal values from the second. Nobody checks this on a plain integer array, though it matters enormously the moment you merge records with keys.

5.4 Dry Run of the Copy Merge

Let us trace with a backup of [1, 2, 3] and a second array of [2, 5, 6]. All three pointers start at 0, and we write from the front. An underscore marks a slot we have not written yet.

Step Backup vs second array Smaller wins Merged so far
1 1 vs 2 1 wins, write 1 [1, _, _, _, _, _]
2 2 vs 2 Tie, take the backup, write 2 [1, 2, _, _, _, _]
3 3 vs 2 2 wins, write 2 [1, 2, 2, _, _, _]
4 3 vs 5 3 wins, write 3 [1, 2, 2, 3, _, _]
5 Backup empty, drain the rest Write 5, then 6 [1, 2, 2, 3, 5, 6]

Let us narrate the pointer dance, step by step.

  • Step 1: both readers sit at the front. Comparing 1 with 2 makes 1 the winner, so it gets written and the backup reader steps forward. The other reader stays put.
  • Step 2: now a 2 meets a 2. It is a tie, so our rule takes from the backup and steps that reader forward again.
  • Step 3: the 3 meets the 2. This time the second array wins, so its reader steps forward instead. Notice the backup reader did not move.
  • Step 4: the 3 meets the 5, and now 3 wins. That pushes the backup reader past its end.
  • Step 5: the backup has run dry, so the main loop stops. The second array still holds 5 and 6 in order, and we pour them straight across.

Once one side empties, no more comparing is needed. Whatever is left is already sorted, so it just gets copied across in order.

5.5 Time and Space Cost

Every value gets read once and written once, so the time cost is O(m + n). That beats the brute force by dropping the log factor entirely.

Space climbs to O(m), because of the backup array. Notice it is O(m) and not O(m + n), since we only ever copy the real values from the first array.

So this approach fixes the speed problem and introduces a memory problem. The third approach fixes both at once.

6. Approach 3: The Three-Pointer Trick

Now for the version interviewers really want. The idea is to fill the first array from the back, using its own empty tail as the workspace. No copy array, no re-sort, just one smart pass.

Think of stacking boxes into a truck from the rear. You place the biggest box last, right at the very back, then work forward. Because the empty space sits at the end, the back is always safe to write.

6.1 Pseudocode

i = m - 1        // last real value in nums1
j = n - 1        // last value in nums2
k = m + n - 1    // last slot in nums1
while j >= 0:
    if i >= 0 and nums1[i] > nums2[j]:
        nums1[k] = nums1[i]; k = k - 1; i = i - 1
    else:
        nums1[k] = nums2[j]; k = k - 1; j = j - 1

This is the clever one, so let us read every line carefully.

  • Line 1: the first reader starts at m minus 1, the last real value in the first array. With m equal to 3 that is slot 2, holding the 3.
  • Line 2: the second reader starts at n minus 1, the last value in the second array. With n equal to 3 that is slot 2, holding the 6.
  • Line 3: the writer starts at m plus n minus 1, the very last slot. With both counts at 3 that is slot 5, the final placeholder.
  • Line 4: the loop runs while the second reader is still zero or higher, meaning values remain to place.
  • Line 5: we check two things at once. Is the first reader still valid, and is its value the bigger one? Both must hold to take from the first array.
  • Lines 6 to 9: the winner drops into the write slot, then that pointer and the supplying reader both step backward.

The trick is direction. We place the biggest remaining value at the back first, then work toward the front. Since the free space sits at the back, the write position never lands on a value we still need.

6.2 Java Code

import java.util.Arrays;

public class MergeSortedArrayThreePointer {
    public static void merge(int[] nums1, int m,
                             int[] nums2, int n) {
        int i = m - 1;
        int j = n - 1;
        int k = m + n - 1;
        while (j >= 0) {
            if (i >= 0 && nums1[i] > nums2[j]) {
                nums1[k--] = nums1[i--];
            } else {
                nums1[k--] = nums2[j--];
            }
        }
    }

    public static void main(String[] args) {
        int[] nums1 = { 1, 2, 3, 0, 0, 0 };
        int[] nums2 = { 2, 5, 6 };
        merge(nums1, 3, nums2, 3);
        System.out.println(Arrays.toString(nums1));
        // Output: [1, 2, 2, 3, 5, 6]
    }
}

6.3 Reading the Code Line by Line

The code mirrors the pseudocode closely. Here is what each part does as it runs.

  • Three setup lines place the pointers at the back: one on the last real value of the first array, one on the last value of the second, and one on the final slot.
  • The loop condition watches the second reader rather than the write position, and the reason gets its own paragraph below.
  • Our comparison asks two questions in order. Does the first array still have values, and is its current value the bigger one? Checking validity first is what stops us reading at a negative position.
  • Whichever value wins gets copied into the write slot, and both that pointer and its reader step one place left.

Why watch the second reader and not the write position? Once the second array empties, whatever remains in the first array is already sorted and already sitting in the correct front slots. So there is nothing left to do, and we stop early.

And why the validity guard? Sometimes the first array runs out of real values before the second does. The guard then fails, we fall into the other branch, and the rest of the second array pours into the front slots. That one small check handles the tricky edge cases for free, and section 7.2 traces exactly that case.

💡 Interview Insight
A classic follow-up asks why we loop on the second array rather than on the write position. The reason is neat: if the second array empties first, every remaining value in the first array is already sitting in its correct spot. So we can stop early and skip pointless writes.

6.4 Time and Space Cost

Each step places exactly one value, and there are m plus n values to place at most. So the time cost is O(m + n), matching the copy merge.

Space never grows beyond three index variables, which puts us at O(1). No backup array, no allocation, nothing to garbage collect.

That combination is why this is the expected answer. It ties the copy merge on speed and ties the brute force on memory, so it loses to neither.

7. Dry Run of the Three-Pointer Approach

Watching the logic run by hand makes it stick. Let us trace [1, 2, 3, 0, 0, 0] with m equal to 3, and [2, 5, 6] with n equal to 3. The readers start at slots 2 and 2, and the writer starts at slot 5. Watch all three slide left.

Step Read positions Comparison First array after step
1 first 2, second 2, write 5 3 vs 6, the 6 is bigger [1, 2, 3, 0, 0, 6]
2 first 2, second 1, write 4 3 vs 5, the 5 is bigger [1, 2, 3, 0, 5, 6]
3 first 2, second 0, write 3 3 vs 2, the 3 is bigger [1, 2, 3, 3, 5, 6]
4 first 1, second 0, write 2 2 vs 2, tie, take the second [1, 2, 2, 3, 5, 6]
5 second reader below zero Loop ends, nothing left to place [1, 2, 2, 3, 5, 6]

Now let us walk through each turn slowly, following where every pointer moves.

  • Step 1: comparing 3 with 6 makes the 6 the winner, so it drops into the last slot. The second reader and the writer both step left, while the first reader stays put.
  • Step 2: the 3 meets the 5. Again the second array wins, so 5 lands in slot 4 and those same two pointers step left.
  • Step 3: the 3 meets the 2, and this time the first array wins. The 3 drops into slot 3, so now the first reader and the writer step left. Notice the 3 barely moved, from slot 2 to slot 3.
  • Step 4: a 2 meets a 2. On a tie our comparison falls into the other branch, so the value comes from the second array and its reader drops below zero.
  • Step 5: with the second reader below zero the loop stops. We never touch the front of the array at all.

Look at step five closely. The values 1 and 2 at the front never moved, because they were already in their correct spots. Stopping early is not laziness, it is the algorithm recognising that the remaining work is already done.

7.1 The Same Dry Run on Paper

Merge Sorted Array problem in DSA three-pointer dry run

The sketch above shows the same trace. The two arrays sit on top, and each step shows the bigger value dropping into the back slot. Many people find this picture easier than the table, so use whichever clicks for you.

7.2 When One Side Empties First

Now the case that breaks careless code. Take a first array of [0, 0, 0] with m equal to 0, and a second array of [2, 5, 6] with n equal to 3.

Here the first array holds no real values at all, so its reader starts at minus 1. It is invalid before the loop even begins.

Step First reader valid? Action First array after step
1 No, it is at -1 Take 6 from the second array [0, 0, 6]
2 No Take 5 from the second array [0, 5, 6]
3 No Take 2 from the second array [2, 5, 6]

The validity guard fails every single time, so every step falls into the other branch and simply copies the second array across in reverse. Result: a correct answer with no special case written anywhere.

Drop that guard and step 1 would read the first array at position minus 1, which crashes immediately. This is the single most common bug in the three-pointer version, and it only shows up on inputs people forget to test.

8. Comparing the Three Approaches

All three approaches give the correct answer. They simply charge different prices for it.

Point Dump and Sort Merge Into a Copy Three Pointer
Time O((m+n) log(m+n)) O(m + n) O(m + n)
Extra space O(1) O(m) O(1)
Uses the sorted inputs No Yes Yes
Direction of writing Not applicable Front to back Back to front
Can stop early No No Yes
Stable on ties Not guaranteed Yes Order still correct
Good for interviews As a starting point As the middle step As the final answer

Read the space row against the time row. Dump and sort is cheap on memory and wasteful on time. The copy merge flips that exactly. Only the three-pointer version refuses to pay either price.

8.1 Which One Should You Pick?

Context decides, and here is the short guide.

  • Reach for the three-pointer version by default. It is linear, in place, and short.
  • Use the copy merge when you need guaranteed stability across equal values.
  • Keep dump and sort for a quick sanity check, or as your opening move on a whiteboard.
  • Never sort when the inputs already arrive sorted, unless you can explain why you threw that away.

In an interview, walk that exact path. Mention dump and sort to show you understand the problem, bring up the copy merge to show you can use the sorted order, then reach for the three-pointer trick to remove the extra space. That climb from blunt to elegant is what interviewers grade you on.

💡 Interview Insight
If the interviewer says memory is tight, the three-pointer trick is your answer. It uses no extra array and still runs in linear time. Saying that trade-off out loud signals real judgment, not just memorised Big-O.

9. Two Common Follow-Ups

Solve the base problem quickly and a follow-up usually arrives. These two show up most often, and both reuse the merge you already know.

9.1 Merging With No Spare Room

Take away the free tail and the problem changes shape. Two ordinary sorted arrays arrive, neither with room to grow, and you must produce a third array holding everything.

Without spare space, an allocation is unavoidable. The good news is that this version is simpler, because writing into a brand new array can never destroy an input.

public class MergeTwoSorted {

    public static int[] mergeTwo(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) {
            if (a[i] <= b[j]) {
                out[k++] = a[i++];
            } else {
                out[k++] = b[j++];
            }
        }
        while (i < a.length) out[k++] = a[i++];
        while (j < b.length) out[k++] = b[j++];
        return out;
    }

    public static void main(String[] args) {
        int[] a = { 1, 4, 7 };
        int[] b = { 2, 3, 9 };
        System.out.println(java.util.Arrays.toString(mergeTwo(a, b)));
        // Output: [1, 2, 3, 4, 7, 9]
    }
}

Look closely and you may recognise this. It is exactly the merge step of merge sort, which is why learning it here pays off twice.

Cost is O(m + n) time and O(m + n) space, and that space is genuinely required, since the output has to live somewhere. Mentioning the merge sort connection out loud is an easy way to show depth.

9.2 Merging More Than Two Sorted Arrays

A natural escalation asks for k sorted arrays instead of two. The obvious move is to fold them together one at a time, merging the running result with the next array.

That works, and it is worth knowing why it disappoints. The running result keeps growing, so early values get copied again on every single merge.

  • Folding one at a time costs about O(k times N), where N is the total number of values.
  • A min-heap holding one candidate per array cuts that to O(N log k).
  • Merging in pairs, tournament style, reaches the same O(N log k) without a heap.

So the answer depends on how large k gets. With three or four arrays, folding is perfectly sensible and much easier to read. With hundreds, the repeated copying dominates and a heap earns its keep.

10. Common Mistakes and Pitfalls

A handful of small traps catch beginners on this problem. Read them once and you will dodge most of them.

  • Treating the trailing zeros as real data. They are empty parking bays, and only the count m tells you where the real values stop.
  • Skipping the validity guard in the three-pointer version. An input where the first array holds no real values then crashes on the very first step.
  • Merging from the front without a backup. The second write lands on a value you have not read yet, and the data is gone.
  • Returning a new array instead of editing in place. The caller keeps looking at the untouched original.
  • Looping on the write position rather than the second array. You then keep writing after the useful work is finished.
  • Sorting the inputs first. They already arrive sorted, so that is pure waste.
  • Assuming duplicates should be removed. Nothing gets dropped here, and the answer always holds exactly m plus n values.

An empty second array needs no special handling either. The loop simply never runs, and the first array is already the correct answer.

11. Practical Walkthrough: Merging Two Score Lists

Let us tie everything into one small program. Two sorted score lists arrive from different sources, and we merge them into one ranked list with a short report.

11.1 The Program

import java.util.Arrays;

public class ScoreMerger {

    public static void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m - 1;
        int j = n - 1;
        int k = m + n - 1;
        while (j >= 0) {
            if (i >= 0 && nums1[i] > nums2[j]) {
                nums1[k--] = nums1[i--];
            } else {
                nums1[k--] = nums2[j--];
            }
        }
    }

    public static void report(int[] nums1, int m, int[] nums2, int n) {
        int[] before = Arrays.copyOf(nums1, m);
        merge(nums1, m, nums2, n);
        System.out.println(Arrays.toString(before) + " + " + Arrays.toString(nums2)
                + " = " + Arrays.toString(nums1) + "  (" + (m + n) + " scores)");
    }

    public static void main(String[] args) {
        report(new int[] { 1, 2, 3, 0, 0, 0 }, 3, new int[] { 2, 5, 6 }, 3);
        report(new int[] { 0, 0, 0 }, 0, new int[] { 2, 5, 6 }, 3);
        report(new int[] { 4, 8 }, 2, new int[] {}, 0);
    }
}
[1, 2, 3] + [2, 5, 6] = [1, 2, 2, 3, 5, 6]  (6 scores)
[] + [2, 5, 6] = [2, 5, 6]  (3 scores)
[4, 8] + [] = [4, 8]  (2 scores)

11.2 What the Output Tells You

Three inputs, three different shapes of answer. That is the point of the exercise.

  • A normal pair merges cleanly, and both 2s survive into the result.
  • An empty first list leans entirely on the validity guard, and every value comes from the second.
  • An empty second list never enters the loop at all, so the first list passes through untouched.

Notice the snapshot taken before merging. Since the merge overwrites in place, printing the original afterwards would be impossible without it. That is the practical cost of an in-place algorithm, and it is worth being aware of.

Notice too how little changed from the bare three-pointer version. The merge is identical, character for character. Everything else exists purely to make the result readable.

12. Interview Questions

Q: What is the Merge Sorted Array problem in DSA?

A: You get two arrays sorted in non-decreasing order. The first has spare room at the end, exactly big enough to hold the second. Your job is to merge the second into the first, in place, so the first ends up fully sorted.

Q: What is the most efficient way to solve it?

A: The three-pointer trick wins. Start both readers at the last real values and the writer at the very last slot, then repeatedly place the larger value at the back. That gives O(m + n) time and O(1) extra space.

Q: Why do we fill from the back instead of the front?

A: The free space sits at the end, so writing there never lands on a value still waiting to be read. Merging from the front would overwrite live data on the second write, unless you back up the originals first.

Q: What do the trailing zeros in the first array mean?

A: Nothing at all. They are placeholders marking empty room, not values. Only the count m tells you where the real data stops, which is exactly why that count is passed in separately.

Q: Why does the loop watch the second array rather than the write position?

A: Once the second array empties, everything left in the first is already sorted and already sitting in the right slots. Stopping there skips pointless writes and finishes early.

Q: Why is the validity guard on the first reader necessary?

A: The first array can run out of real values before the second does, pushing its reader below zero. Checking validity before reading avoids an out-of-bounds crash and lets the remaining values pour in.

Q: Why not just dump everything together and sort?

A: That works, and it costs O((m + n) log (m + n)) time. It also throws away the sorted order you were handed for free, which is precisely the thing the question is testing.

Q: How does this relate to merge sort?

A: Very directly. Combining two sorted lists into one is the merge step of merge sort. Learn it here and you have learned half of that algorithm already.

Q: How would I merge more than two sorted arrays?

A: Folding them one at a time costs roughly O(k times N), because early values get recopied repeatedly. A min-heap holding one candidate per array, or pairwise tournament merging, brings that down to O(N log k).

Q: Which edge cases should I test before I say I am done?

A: Try an empty second array, a first array with no real values, arrays where one is entirely larger than the other, and inputs full of duplicates. Those four catch nearly every bug here.

13. Conclusion

Let us wrap up what we covered. The Merge Sorted Array problem in DSA looks like a warm-up, and it is. Yet the fill-from-the-back idea inside it is a real skill you will reuse constantly.

We started with dump and sort. Pour the second array into the spare tail, sort everything, done. Correct and short, at a cost of O((m + n) log (m + n)) and a sorted order thrown away for nothing.

The copy merge came next and removed that waste. Back up the real values, walk both sorted lists side by side, and always take the smaller front value. Linear time, at the price of an O(m) backup array.

Three pointers finished the job by refusing both prices. Start at the back, place the larger value into the spare tail, and walk everything leftward. Linear time with constant space, and it stops early the moment the second array runs dry.

Along the way we handled the usual follow-ups. Without a spare tail you must allocate, and that merge is exactly merge sort’s merge step. With many arrays instead of two, a heap replaces repeated folding.

So take the pattern, not just the answer. When free space sits at one end, write towards it, and your writer can never trample a value your reader still needs. Once that habit feels natural, a whole family of in-place array problems opens up.

14. Further Reading

  • Previous in this series: Move Zeroes problem in DSA — pull the non-zero values forward and park the zeroes at the end in one pass.
  • Coming next in this series: Valid Palindrome — walk two pointers inward from both ends to check whether a string reads the same both ways.
  • Maximum Subarray problem in DSA — Kadane’s Algorithm finds the largest sum of any contiguous slice in one sweep.
  • Contains Duplicate problem in DSA — another single-pass array question, this time about membership.
  • Arrays in Java — brush up on indexing and iteration before tackling more array puzzles.
  • LeetCode Merge Sorted Array — practise the original problem and submit your own solution.

Leave a Comment