DSA sheet · Binary Search · Classic binary search pattern

Search Insert Position

Third question of the classic pattern (LeetCode 35). It's Binary Search Basics with one twist: if the target is not in the array, we don't return −1. We return the index where it should go so the array stays sorted. The teacher first writes a simple linear scan, uses the constraints to explain when that stops being enough, and then writes binary search. Its only change from the basic template is the last line: return left.

Why it matters: "where would this value go?" is the idea behind lower bound, floor/ceiling, first occurrence and many later problems. The question "why left and not right?" is the first real taste of thinking about where the pointers end up.

Every part below follows the same order:
① the question in simple words → ② what the constraints tell us → ③ intuition → ④ building the conditions from examples → ⑤ approach steps → ⑥ code → ⑦ code line by line → ⑧ dry run → ⑨ complexity & remember

Part 0 · Before starting

Words we will use

Why binary search works here

The array is sorted. Ask "is nums[i] >= target?" for each i. Because the array only grows, the answers look like no no no yes yes yes. They flip once. The insert position is exactly the first "yes" (or n if there is no "yes"). A yes/no that flips once is what binary search needs: at mid, the answer tells us which side the flip is on.

The mid formula

We write mid = left + (right - left) // 2. It gives the same index as (left + right) // 2. The teacher repeats the reason: in Java/C++, if right is huge, left + right can go past the int limit and become negative (overflow). Subtracting first keeps the numbers small. Python ints never overflow, so here it's just a good habit. With n ≤ 10⁴ even Java would be fine with the simple form.


Part A · Linear scan: the first index with value ≥ target

LeetCode 35

1The question in simple words

You get a sorted array of distinct integers (no repeats) and a target.

index0123
value1356

target 5 → 2 (found) · target 2 → 1 (goes between 1 and 3) · target 7 → 4 (after the end) · target 0 → 0 (before everything).

2What the constraints tell us

3Intuition

Say we must insert 3 into an array that starts 1, 2, 4, … Looking at it, we know right away that 3 goes after 2 and before 4. The code doesn't "see" that, so it has to walk through the items one by one.

4Building the conditions from examples

Insert 3 into an array that starts 1 2 4 …:

Rule so far: the first index where nums[i] > target is the answer.

Why >= and not just >

If the target is already in the array (e.g. the value at index 2 were 3 itself), the question says return that index. So "equal" must also stop the loop and return i. The condition becomes nums[i] >= target.

What if nothing is ≥ target?

Say we insert 10 and every value is smaller. The loop finishes without returning. Where does 10 go? After the last item. The last index is n − 1, so one after it is (n − 1) + 1 = n. Return len(nums).

5Approach steps

  1. For i from 0 to n − 1: if nums[i] >= target → return i.
  2. After the loop → return n.

6Code (Python)

Search Insert Position, linear scan
class SolutionLinear:
    def searchInsert(self, nums, target):
        n = len(nums)
        for i in range(n):
            if nums[i] >= target:   # found it, or found where it fits
                return i
        return n                    # bigger than everything: goes at the end

7Code line by line

linewhat it means
for i in range(n):Walk the array from the left, one index at a time.
if nums[i] >= target:Everything before i was smaller than the target. If this value is equal, the target is here. If it's bigger, the target slides in here.
return iEither way, i is the answer.
return nNo value was ≥ target, so it goes after the last index (n − 1 + 1 = n).

8Dry run

arraytargetwalkanswer
1 3 5 651 < 5, 3 < 5, 5 ≥ 52
1 3 5 621 < 2, 3 ≥ 21
1 3 5 67all smaller, loop ends4 (= n)
1 3 5 601 ≥ 0 right away0

9Complexity & remember

Remember the linear scanReturn the first i with nums[i] >= target. If none, return n. >= (not >) handles "target already present".

Part B · Binary search, return left

1The question

Same question. Now in O(log n), using the sorted order.

2What the constraints tell us

Same as Part A. Binary search is what makes this survive if n were 10⁹. Small values mean no overflow worries even in Java.

3Intuition

Why always the middle? Because comparing with the middle lets us drop half of the array with one decision. If the middle value is bigger than the target, the target belongs somewhere on the left, so the right half can go. If it's smaller, the left half can go.

We keep doing this until the range is empty. The new idea: when the range becomes empty, left is sitting exactly at the insert position.

4Building the conditions from examples

The teacher's board shows a 7-item sorted array (indexes 0 to 6) and target 3, which isn't in it. We'll use 1 2 4 5 6 8 9, which starts 1, 2, 4 like her linear-search walk.

index0123456
value1245689left 0, right 6, mid 3

Following her board: after the first step the range is indexes 0–2. The middle there (value 2) is smaller than 3, so we move right. Now left, right and mid all land on the same index (2, value 4). She points out that when the range shrinks to a single index like this, that's where 3 belongs. 4 > 3 moves right to 1, the pointers cross, and left = 2 is the answer.

Loop condition: keep going while left <= right ("until left crosses right, and also when they're equal"), the same as basic binary search.

Why return left and not right?

The teacher's advice is to dry run it with pen and paper on different test cases and see for yourself. Her short reason: when they cross, right has stepped back to a place left was at earlier, a place already found to be too small, and that's why left moved past it. So left is the correct spot.

Doubt: can we say this more precisely?
→ Watch what each pointer promises:
• left only moves to mid + 1 after nums[mid] < target. So everything before left is smaller than the target.
• right only moves to mid - 1 after nums[mid] > target. So everything after right is bigger than the target.
When the loop ends, right = left − 1, so every index is on one side or the other. Everything before left is smaller and everything from left onward is bigger. That boundary is exactly the insert position: left. right is one step short.
Doubt: show me a case where returning right fails.
→ [1, 3, 5, 6], target 0. The loop keeps moving right left: right ends at −1, which isn't even a valid index. left stays at 0 ✓. In fact right is always one less than the answer when the target is missing, e.g. target 2 → right ends at 0, but the answer is 1.
Doubt: what about target bigger than everything?
→ Every mid is smaller, so left keeps moving right until it passes the last index: left = n. That's exactly "insert at the end", the same as return n in Part A. No special case needed.
Doubt: are there other ways to write it?
→ Yes. The teacher mentions you could, for example, keep a separate "answer so far" variable and save mid into it, or move right to mid instead of mid - 1. There are many correct versions. Two of them are shown at the end of step 6. They all compute the same thing: the first index with value ≥ target.

5Approach steps

  1. left = 0, right = n - 1.
  2. While left <= right: mid = left + (right - left) // 2.
  3. nums[mid] == target → return mid.
  4. nums[mid] > target → right = mid - 1.
  5. Else → left = mid + 1.
  6. After the loop → return left.

6Code (Python)

Search Insert Position, binary search
class Solution:
    def searchInsert(self, nums, target):
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] == target:
                return mid              # already present
            elif nums[mid] > target:
                right = mid - 1         # it belongs on the left
            else:
                left = mid + 1          # it belongs on the right
        return left                     # where the target would be inserted
other correct ways she mentions (optional)
class SolutionSaveAnswer:               # keep the best answer seen so far
    def searchInsert(self, nums, target):
        left, right = 0, len(nums) - 1
        ans = len(nums)                 # default: insert at the end
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] >= target:
                ans = mid               # mid works; maybe something earlier does too
                right = mid - 1
            else:
                left = mid + 1
        return ans

class SolutionRightIsMid:               # move right to mid, not mid - 1
    def searchInsert(self, nums, target):
        left, right = 0, len(nums)      # right = n: "at the end" is possible
        while left < right:             # stop when one candidate is left
            mid = left + (right - left) // 2
            if nums[mid] >= target:
                right = mid             # mid could be the answer, keep it
            else:
                left = mid + 1
        return left

7Code line by line

linewhat it means
left = 0 right = len(nums) - 1Search the whole array.
while left <= right:Until the pointers cross. When they're equal, one index is still unchecked.
mid = left + (right - left) // 2The middle index, overflow-safe form.
if nums[mid] == target: return midTarget present: return its index.
elif nums[mid] > target: right = mid - 1mid and everything after it are bigger. Drop them.
else: left = mid + 1mid and everything before it are smaller. Drop them.
return leftThe only line that differs from basic binary search (which returns −1). Everything before left is smaller, everything from left on is bigger, so left is where the target fits.
SolutionSaveAnswerSame loop, but every time a mid is ≥ target it's saved as a possible answer, and we keep looking left for an earlier one.
SolutionRightIsMidBoundary style: right starts at n, right = mid keeps mid as a candidate, and the loop is < so it can't get stuck.

8Dry run

Her board example: target 3 in 1 2 4 5 6 8 9

stepleftrightmidnums[mid]decisionwhat we throw away
106355 > 3 → right = 25 6 8 9
202122 < 3 → left = 21 2
322244 > 3 → right = 14
end21crossed → return left = 2 (3 goes between 2 and 4). right = 1 would be wrong.
step 11245689
step 21245689
step 31245689left = right = mid = 2
result123456893 inserted at index 2 → still sorted ✓

Edge cases on 1 3 5 6

targetsteps (left, right, mid → decision)endanswer
5(0,3,1): 3 < 5 → left 2 · (2,3,2): 5 = 5found2
7(0,3,1): 3 < 7 → left 2 · (2,3,2): 5 < 7 → left 3 · (3,3,3): 6 < 7 → left 4left 4, right 34 (= n)
0(0,3,1): 3 > 0 → right 0 · (0,0,0): 1 > 0 → right −1left 0, right −10

9Complexity & remember

Remember Search Insert PositionBasic binary search, but return left instead of −1. left = "everything before me is smaller". right ends one step before it.

The teacher's closing advice: watching isn't learning. Dry run it yourself on paper with a few targets (found, between, before all, after all), then write and submit the code yourself. Otherwise the "why left" logic won't stick.


Part C · Revision page

linear scanbinary search
ideafirst i with nums[i] >= targetbasic binary search, then return left
not foundreturn nreturn left (which is n when the target is bigger than all)
timeO(n) (TLE if n were 10⁹)O(log n)
spaceO(1)O(1)
casewhere left endswhere right ends
target smaller than all0 ✓−1
target between two valuesindex of the bigger neighbour ✓index of the smaller neighbour
target bigger than alln ✓n − 1
target presentreturned from inside the loop (mid)
If you remember only 5 lines 1. Insert position = first index whose value is ≥ target (n if none).
2. Linear: if nums[i] >= target: return i, then return n.
3. Binary: same loop as basic binary search (<=, mid ± 1).
4. Only change: return left after the loop.
5. Before left: all smaller. After right: all bigger. They end next to each other.
Mistakes to avoid ✗ > instead of >= in the linear scan (when the target is present, it skips it and returns the next index)
✗ returning right (one too small, −1 for "before all")
✗ returning −1 out of habit from basic binary search
✗ forgetting the "insert at the end" case (n, not n − 1)
test it yourself (paste under the solutions above)
for S in (SolutionLinear, Solution, SolutionSaveAnswer, SolutionRightIsMid):
    s = S()
    print(s.searchInsert([1, 3, 5, 6], 5), s.searchInsert([1, 3, 5, 6], 2),
          s.searchInsert([1, 3, 5, 6], 7), s.searchInsert([1, 3, 5, 6], 0),
          s.searchInsert([1, 2, 4, 5, 6, 8, 9], 3))
# 2 1 4 0 2  (printed 4 times)

Based on this video: Search Insert Position | Classic Binary Search pattern