Without Constraints, Any Solution Works. That's Exactly the Problem.
Most people read a problem looking for what they need to do.
Senior engineers read it looking for what the problem is already telling them.
That difference — subtle, almost invisible — is responsible for some of the most elegant solutions I’ve ever seen. And some of the most expensive mistakes I’ve watched teams make.
Let me show you what I mean.
Constraints Are Not Limitations. They Are Instructions.
Open Google Maps and ask for directions with zero preferences. No restrictions, no filters, no “avoid tolls”, no “avoid highways.” The app will give you a route. Probably a fine one.
Now turn on “avoid tolls”, set your vehicle as a motorcycle, and tell it you need to arrive before 9am. Watch what happens. Most of the options disappear. The map stops showing you everything that’s possible and starts showing you what actually fits.
The constraints didn’t make the problem harder. They made the answer clearer.
This is one of the most underappreciated ideas in engineering: a well-defined constraint isn’t an obstacle. It’s a shortcut to the right answer.
The problem I want to walk through is called “Merge Sorted Array.” You have two lists of numbers, both already sorted from smallest to largest. Your job is to combine them into one single sorted list.
Without constraints, you have dozens of valid approaches. Some fast, some slow, some that quietly waste memory every time they run.
But there’s one constraint that changes everything — and most people read right past it:
The first list was deliberately built with empty slots at the end. Those slots are reserved exactly for the numbers that are coming in.
Those empty slots aren’t a formatting quirk. They aren’t filler. They were put there intentionally — because whoever designed this problem knew exactly what the solution should look like.
The question is: will you notice them before you reach for a blank sheet of paper?
The Pragmatic Solution — Correct, But Blind to the Most Important Detail
Let me make this concrete.
Two sales teams just merged into one company. Team A has a ranked list of leads, ordered by deal size — biggest opportunity at the top. Team B has their own ranked list, also ordered. Leadership wants one unified pipeline: a single list, still ordered, with everyone included.
Your first instinct — and it’s a perfectly reasonable one — is this:
Grab a blank sheet of paper. Put both lists side by side. Look at the top lead on each list. Write down whichever deal is smaller on your blank sheet. Cross that lead off its original list. Look at the top of each list again. Repeat until both lists are empty. Copy the blank sheet back into the official system.
Done. It works. It’s clean. It’s logical.
But Team A’s spreadsheet already had empty rows at the bottom — added specifically because this merger was planned months ago. And you grabbed a blank sheet of paper anyway.
You solved the problem. You just ignored the most useful piece of information you were given.
Now let’s build this solution in code, one piece at a time.
Step 1 — Set up your two fingers and the blank sheet
You need one finger pointing at the top of each list, and an empty place to write your results:
let p1 = 0 // finger on list 1, starting at position 0
let p2 = 0 // finger on list 2, starting at position 0
let result = [] // the blank sheet of paperStep 2 — Walk through both lists, comparing as you go
At every step, you look at what each finger is pointing at and write down the smaller one:
for (let i = 0; i < m + n; i++) {
} else if (nums1[p1] <= nums2[p2]) {
// list 1's current item is smaller — write it, move finger forward
result.push(nums1[p1++])
} else {
// list 2's current item is smaller — write it, move finger forward
result.push(nums2[p2++])
}
}Step 3 — Handle the edge case: one list runs out before the other
When one list is empty, stop comparing — just drain whatever is left from the other:
if (p1 >= m) {
// list 1 is finished — take the rest of list 2 directly
result.push(nums2[p2++])
} else if (p2 >= n) {
// list 2 is finished — take the rest of list 1 directly
result.push(nums1[p1++])
}Step 4 — Copy the blank sheet back into the original list
nums1.splice(0, m + n, ...result)The complete solution:
var merge = function(nums1, m, nums2, n) {
let p1 = 0
let p2 = 0
let result = []
for (let i = 0; i < m + n; i++) {
if (p1 >= m) {
result.push(nums2[p2++])
} else if (p2 >= n) {
result.push(nums1[p1++])
} else if (nums1[p1] <= nums2[p2]) {
result.push(nums1[p1++])
} else {
result.push(nums2[p2++])
}
}
nums1.splice(0, m + n, ...result)
}It works. But result = [] is the blank sheet of paper — memory that didn’t need to exist. And nums1.splice(...) at the end is the trip back to the office to copy everything over — work that didn’t need to happen. Both costs exist only because we didn’t stop to ask why those empty slots were there.
The Engineered Solution — Using What Was Already There
Same two sales teams. Same two lists. Same goal.
This time, before doing anything, you notice the empty rows at the bottom of Team A’s spreadsheet. And you ask the question most people don’t:
Why are these here?
There are exactly as many empty rows as there are leads in Team B’s list. Someone left you exactly the space you need, exactly where you need it.
So instead of grabbing a blank sheet of paper, you try something different. You don’t start from the top. You start from the bottom.
Look at the last lead on Team A’s list and the last lead on Team B’s list. Whichever deal is larger — whichever one ranks lowest in the final unified list — goes into the last empty row. Cross it off. Compare again. Place the larger one in the second-to-last empty row. Keep going, filling from the bottom up.
Because you’re always writing into empty space, you never accidentally overwrite a lead you still need. No blank sheet. No copying back. Everything lands exactly where it needs to go, in a single pass.
Let’s build this one step at a time too.
Step 1 — Set up your fingers, but this time starting from the end
Instead of starting at the top of each list, you start at the bottom. And instead of writing onto a blank sheet, you write directly into the empty slots:
let p1 = m - 1 // finger at the LAST real item in list 1
let p2 = n - 1 // finger at the LAST item in list 2
let i = m + n - 1 // pointer at the LAST empty slotStep 2 — Compare from the end, place the larger item into the last empty slot
The logic is the same as before — compare two items, pick one — but now you’re moving backward and picking the larger one each time:
if (p1 >= 0 && nums1[p1] > nums2[p2]) {
// list 1's current item is larger
// place it at the current empty slot, move both pointers back
nums1[i--] = nums1[p1--]
} else {
// list 2's current item is larger (or list 1 is exhausted)
// place it at the current empty slot, move both pointers back
nums1[i--] = nums2[p2--]
}Step 3 — Keep going until list 2 is fully placed
You only need to keep going while list 2 still has items. Once list 2 is exhausted, anything remaining in list 1 is already exactly where it belongs — no action needed:
while (p2 >= 0) {
// keep going as long as list 2 still has items
}The complete solution:
var merge = function(nums1, m, nums2, n) {
let p1 = m - 1
let p2 = n - 1
let i = m + n - 1
while (p2 >= 0) {
if (p1 >= 0 && nums1[p1] > nums2[p2]) {
nums1[i--] = nums1[p1--]
} else {
nums1[i--] = nums2[p2--]
}
}
}No extra memory. No extra steps. The constraint, finally being used for what it was always there for.
What This Actually Takes
Both solutions produce identical results. A user running either one would never notice a difference.
But the distance between them isn’t technical knowledge. It’s reading discipline.
The first solution was written by someone who read the problem until they understood what needed to be done. The second was written by someone who read it until they understood what the problem was already offering.
That habit — slowing down before reaching for a solution, asking what the constraints are actually telling you — doesn’t just produce better code. It produces better architecture decisions, better product scoping, better conversations between engineers and founders about what’s actually worth building and what’s expensive noise.
Constraints well understood don’t restrict your options. They collapse a hundred mediocre solutions down to the one that fits.
The array already had the answer. It was in the empty slots the whole time. You just had to stop and ask why they were there.

