Merge sorted nums2 into sorted nums1 in place. The trick: fill from the backwith three pointers, so you never overwrite a value you haven't read yet.
Two sorted arrays, merged into one sorted array — but written back into nums1, which already has n empty slots at the end. nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 → [1,2,2,3,5,6]. No new array allowed; do it in place.
nums1, and the largest merged value belongs at the end. So write back-to-front: compare the two current largest values and drop the bigger one into the rightmost open slot. Because that slot is always at or beyond every value you still need to read, you never clobber unread data.i = m - 1 (last real value in nums1), j = n - 1 (last in nums2), k = m + n - 1 (last slot — where we write).j >= 0: if nums1[i] > nums2[j], write nums1[i] and i--; otherwise write nums2[j] and j--. Either way k--.j runs out. Loop on j, not i: any leftover nums1 values are already sitting in their final sorted positions — nothing to move.i >= 0. If nums1 is exhausted first, fall through to copying the rest of nums2.nums1 values you still need to read. Going backward sidesteps the whole problem — no temp array required.A forward merge into a fresh array is also O(m + n) time but needs O(m + n) extra space (or careful shifting). The back-to-front trick is what buys you O(1) extra space while staying linear.
i = 2 (last real value in nums1), j = 2 (last in nums2), k = 5 (last slot to write).1function merge(nums1: number[], m: number, nums2: number[], n: number): void {2▶ let i = m - 1; // last real value in nums13▶ let j = n - 1; // last value in nums24▶ let k = m + n - 1; // last slot overall (write here)56 while (j >= 0) { // while nums2 still has values to place7 if (i >= 0 && nums1[i] > nums2[j]) {8 nums1[k] = nums1[i]; // nums1's value is bigger → take it9 i--;10 } else {11 nums1[k] = nums2[j]; // nums2's value wins (or nums1 exhausted)12 j--;13 }14 k--; // move the write pointer left15 }16}
function merge(nums1: number[], m: number, nums2: number[], n: number): void {
let i = m - 1; // last real value in nums1
let j = n - 1; // last value in nums2
let k = m + n - 1; // last slot overall (write here)
while (j >= 0) { // while nums2 still has values to place
if (i >= 0 && nums1[i] > nums2[j]) {
nums1[k] = nums1[i]; // nums1's value is bigger → take it
i--;
} else {
nums1[k] = nums2[j]; // nums2's value wins (or nums1 exhausted)
j--;
}
k--; // move the write pointer left
}
}i points at the last real value of nums1, j at the last of nums2, and k at the very last slot (m + n - 1) where the next merged value will be written.j. We only need to keep going while nums2 still has values to place. When j hits -1, every remaining nums1 value is already in its correct spot.i >= 0 guard prevents reading past the front of nums1. If nums1[i] > nums2[j], copy it down to nums1[k] and step i left.nums1 is exhausted, i < 0) drop nums2[j] into nums1[k] and step j left.k-- moves the write head one slot left. The loop exits with nums1 fully merged and no extra array allocated.nums1 with three index pointers.nums1 values you still need to read.j and not i?" Leftover nums1 values are already in place; only unplaced nums2 values force more work.nums1 empties first?" The i >= 0 guard sends control to the else branch, copying the rest of nums2 straight down.function merge(nums1: number[], m: number, nums2: number[], n: number): void {
let i = m - 1; // last real value in nums1
let j = n - 1; // last value in nums2
let k = m + n - 1; // last slot overall (write here)
while (j >= 0) { // while nums2 still has values to place
if (i >= 0 && nums1[i] > nums2[j]) {
nums1[k] = nums1[i]; // nums1's value is bigger → take it
i--;
} else {
nums1[k] = nums2[j]; // nums2's value wins (or nums1 exhausted)
j--;
}
k--; // move the write pointer left
}
}nums1 with three index pointers.Copy nums2 over the trailing zeros, then sort the whole thing — the shortest correct answer, useful to state before optimizing.
function merge(nums1: number[], m: number, nums2: number[], n: number): void {
for (let k = 0; k < n; k++) {
nums1[m + k] = nums2[k];
}
nums1.sort((a, b) => a - b);
} O((m+n) log(m+n)) sort instead of a linear merge. The three-pointer back-merge is O(m + n).The classic two-array merge: walk both forward, take the smaller, then copy back. Easy to reason about, but needs a scratch array.
function merge(nums1: number[], m: number, nums2: number[], n: number): void {
const merged: number[] = [];
let i = 0, j = 0;
while (i < m && j < n) {
merged.push(nums1[i] <= nums2[j] ? nums1[i++] : nums2[j++]);
}
while (i < m) merged.push(nums1[i++]);
while (j < n) merged.push(nums2[j++]);
for (let k = 0; k < m + n; k++) nums1[k] = merged[k];
}merged array costs O(m + n) space. Merging from the back inside nums1 avoids the allocation entirely.| merge two SORTED arrays | two pointers, take the smaller/larger |
| in place, extra space at the end | fill from the back (k = m+n-1) |
| risk of overwriting unread data | walk pointers toward the free end |
| combine many sorted runs | min-heap of heads (k-way merge) |
let i = m - 1, j = n - 1, k = m + n - 1;
while (j >= 0) {
if (i >= 0 && nums1[i] > nums2[j]) {
nums1[k--] = nums1[i--];
} else {
nums1[k--] = nums2[j--];
}
}i = m - 1, j = n - 1, k = m + n - 1 — all at the back.