35. Search Insert Position
Problem Description
You are given a sorted array of distinct integers and a target value. Your task is to find where the target value should be placed in the array to maintain the sorted order.
If the target value already exists in the array, return its index. If the target value doesn't exist, return the index where it would be inserted to keep the array sorted.
For example:
- If
nums = [1, 3, 5, 6]
andtarget = 5
, the function should return2
because 5 exists at index 2 - If
nums = [1, 3, 5, 6]
andtarget = 2
, the function should return1
because 2 would be inserted at index 1 to maintain sorted order - If
nums = [1, 3, 5, 6]
andtarget = 7
, the function should return4
because 7 would be inserted at the end
The algorithm must have O(log n)
runtime complexity, which means you need to use binary search rather than a linear scan through the array.
The solution uses binary search to efficiently find the insertion position. It maintains two pointers l
(left) and r
(right) to define the search range. In each iteration, it calculates the middle index and compares nums[mid]
with the target. If nums[mid] >= target
, it means the target should be inserted at or before the middle position, so the search continues in the left half. Otherwise, the search continues in the right half. When the loop ends, l
points to the correct insertion position.
Intuition
Since we need O(log n)
complexity and the array is sorted, binary search is the natural choice. The key insight is that we're not just searching for an exact match - we're looking for the correct insertion position.
Think of binary search as repeatedly dividing the search space in half. At each step, we compare the middle element with our target. If nums[mid] >= target
, we know the target belongs somewhere in the left half (including possibly at the current middle position). If nums[mid] < target
, the target must go somewhere in the right half.
The clever part is recognizing that we want to find the leftmost position where we could insert the target. This is why when nums[mid] >= target
, we set r = mid
(not mid - 1
). We're saying "the answer could be at mid
or somewhere to its left." When nums[mid] < target
, we know for certain the answer is to the right of mid
, so we set l = mid + 1
.
By the time our search window shrinks to nothing (l >= r
), l
will be pointing exactly where the target should go:
- If the target exists,
l
points to its position - If the target doesn't exist,
l
points to where it would maintain sorted order
This approach elegantly handles both cases (element exists or doesn't exist) with the same logic, avoiding the need for special case handling.
Learn more about Binary Search patterns.
Solution Approach
The implementation uses binary search with a two-pointer approach. Here's how the algorithm works step by step:
Initial Setup:
- Initialize
l = 0
(left boundary) andr = len(nums)
(right boundary) - Note that
r
is set to the array length, notlen(nums) - 1
, allowing us to handle insertion at the end of the array
Binary Search Loop:
The loop continues while l < r
:
-
Calculate the middle index:
mid = (l + r) >> 1
- The
>> 1
operation is a bitwise right shift, equivalent to integer division by 2 - This efficiently finds the midpoint of our current search range
- The
-
Compare
nums[mid]
withtarget
:- If
nums[mid] >= target
: Setr = mid
- This means the target should be at position
mid
or somewhere to its left - We keep
mid
in our search range because it could be the answer
- This means the target should be at position
- If
nums[mid] < target
: Setl = mid + 1
- The target must be inserted after position
mid
- We can safely exclude
mid
from our search range
- The target must be inserted after position
- If
Loop Termination:
When l >= r
, the search window has converged to a single position. At this point, l
represents:
- The index of the target if it exists in the array
- The index where the target should be inserted if it doesn't exist
Return Value:
The function returns l
, which is the correct insertion position.
Example Walkthrough:
For nums = [1, 3, 5, 6]
and target = 2
:
- Initial:
l = 0
,r = 4
- Iteration 1:
mid = 2
,nums[2] = 5 >= 2
, sor = 2
- Iteration 2:
mid = 1
,nums[1] = 3 >= 2
, sor = 1
- Iteration 3:
mid = 0
,nums[0] = 1 < 2
, sol = 1
- Loop ends as
l == r == 1
- Returns
1
, the correct insertion position
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through finding the insertion position for target = 4
in the array nums = [1, 3, 5, 7, 9]
.
Initial State:
- Array:
[1, 3, 5, 7, 9]
- Target:
4
(doesn't exist, should go between 3 and 5) l = 0
,r = 5
(array length)
Iteration 1:
- Calculate
mid = (0 + 5) >> 1 = 2
- Check
nums[2] = 5
- Since
5 >= 4
, the target belongs at position 2 or to its left - Update:
r = 2
- Search range:
[1, 3, 5]
(indices 0-1, with 2 as potential answer)
Iteration 2:
- Calculate
mid = (0 + 2) >> 1 = 1
- Check
nums[1] = 3
- Since
3 < 4
, the target must go after position 1 - Update:
l = 2
- Search range narrows to index 2
Termination:
- Now
l = 2
andr = 2
, sol >= r
- Loop ends
- Return
l = 2
Verification:
Inserting 4 at index 2 would give us [1, 3, 4, 5, 7, 9]
, which maintains sorted order. The algorithm correctly identified that 4 should be placed where 5 currently is, shifting 5 and subsequent elements to the right.
Key Insight: Notice how the algorithm naturally converges to the correct position. When we find an element greater than or equal to our target (5 in this case), we keep it as a candidate position. When we find an element less than our target (3 in this case), we know the answer must be after it. The two pointers eventually meet at the exact insertion point.
Solution Implementation
1class Solution:
2 def searchInsert(self, nums: List[int], target: int) -> int:
3 """
4 Find the index where target should be inserted in a sorted array.
5 If target exists, return its index. Otherwise, return the insertion position.
6
7 Args:
8 nums: A sorted array of integers in ascending order
9 target: The target value to search for or insert
10
11 Returns:
12 The index where target is found or should be inserted
13 """
14 # Initialize binary search boundaries
15 # left points to the start, right points one past the end (exclusive)
16 left, right = 0, len(nums)
17
18 # Binary search to find the leftmost position where nums[i] >= target
19 while left < right:
20 # Calculate middle index using bit shift (equivalent to // 2)
21 mid = (left + right) >> 1
22
23 # If middle element is greater than or equal to target,
24 # the answer is in the left half (including mid)
25 if nums[mid] >= target:
26 right = mid
27 else:
28 # Otherwise, the answer is in the right half (excluding mid)
29 left = mid + 1
30
31 # left now points to the first position where nums[i] >= target
32 # or to len(nums) if all elements are smaller than target
33 return left
34
1class Solution {
2 public int searchInsert(int[] nums, int target) {
3 // Initialize binary search boundaries
4 // left: inclusive start index
5 // right: exclusive end index (initially set to array length)
6 int left = 0;
7 int right = nums.length;
8
9 // Binary search loop continues while search space is not empty
10 while (left < right) {
11 // Calculate middle index using unsigned right shift to avoid overflow
12 // Equivalent to (left + right) / 2 but prevents integer overflow
13 int mid = (left + right) >>> 1;
14
15 // Check if middle element is greater than or equal to target
16 if (nums[mid] >= target) {
17 // Target is in the left half (including mid)
18 // Move right boundary to mid (exclusive)
19 right = mid;
20 } else {
21 // Target is in the right half (excluding mid)
22 // Move left boundary to mid + 1 (inclusive)
23 left = mid + 1;
24 }
25 }
26
27 // Return the insertion position
28 // At this point, left == right, representing the smallest index
29 // where nums[index] >= target, or array length if target > all elements
30 return left;
31 }
32}
33
1class Solution {
2public:
3 int searchInsert(vector<int>& nums, int target) {
4 // Initialize binary search boundaries
5 // left: inclusive start index
6 // right: exclusive end index (nums.size())
7 int left = 0;
8 int right = nums.size();
9
10 // Binary search to find the leftmost position where target should be inserted
11 while (left < right) {
12 // Calculate middle index using bit shift (equivalent to dividing by 2)
13 int mid = (left + right) >> 1;
14
15 // If middle element is greater than or equal to target,
16 // the insertion position is at mid or to the left of mid
17 if (nums[mid] >= target) {
18 right = mid; // Narrow search to left half (excluding mid)
19 } else {
20 // If middle element is less than target,
21 // the insertion position is to the right of mid
22 left = mid + 1; // Narrow search to right half (excluding mid)
23 }
24 }
25
26 // When left == right, we've found the insertion position
27 // This is the smallest index where nums[index] >= target
28 // or nums.size() if all elements are smaller than target
29 return left;
30 }
31};
32
1/**
2 * Binary search to find the index where target should be inserted in a sorted array
3 * @param nums - Sorted array of numbers in ascending order
4 * @param target - Target value to search for or insert
5 * @returns The index where target is found or should be inserted to maintain sorted order
6 */
7function searchInsert(nums: number[], target: number): number {
8 // Initialize binary search boundaries
9 // left starts at 0, right starts at array length (exclusive)
10 let left: number = 0;
11 let right: number = nums.length;
12
13 // Continue binary search while search space is valid
14 while (left < right) {
15 // Calculate middle index using bit shift for integer division
16 // Equivalent to Math.floor((left + right) / 2)
17 const middle: number = (left + right) >> 1;
18
19 // If middle element is greater than or equal to target,
20 // search in the left half (including middle)
21 if (nums[middle] >= target) {
22 right = middle;
23 } else {
24 // If middle element is less than target,
25 // search in the right half (excluding middle)
26 left = middle + 1;
27 }
28 }
29
30 // Return the insertion position
31 // At this point, left === right, representing the correct position
32 return left;
33}
34
Time and Space Complexity
The time complexity is O(log n)
, where n
is the length of the array nums
. This is because the algorithm uses binary search, which divides the search space in half with each iteration. The while loop continues until l < r
is false, and in each iteration, we either set r = mid
or l = mid + 1
, effectively halving the search range. Therefore, the maximum number of iterations is log₂(n)
.
The space complexity is O(1)
as the algorithm only uses a constant amount of extra space. The variables l
, r
, and mid
are the only additional space used, regardless of the input size. No recursive calls are made, and no additional data structures are created that depend on the input size.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Right Boundary Initialization
One of the most common mistakes is initializing right = len(nums) - 1
instead of right = len(nums)
. This seems intuitive since array indices go from 0 to len(nums) - 1
, but it causes problems when the target should be inserted at the end of the array.
Incorrect Implementation:
def searchInsert(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1 # Wrong!
while left < right:
mid = (left + right) >> 1
if nums[mid] >= target:
right = mid
else:
left = mid + 1
return left
Problem: When target = 7
and nums = [1, 3, 5, 6]
, this returns index 3 instead of 4. The algorithm never considers position 4 as a valid insertion point.
Solution: Always use right = len(nums)
to include the position after the last element as a valid insertion point.
2. Infinite Loop with Wrong Update Logic
Another pitfall occurs when using left <= right
as the loop condition with incorrect pointer updates.
Incorrect Implementation:
def searchInsert(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right: # Different condition
mid = (left + right) >> 1
if nums[mid] >= target:
right = mid # This can cause infinite loop!
else:
left = mid + 1
return left
Problem: When left == right
, setting right = mid
doesn't change the search range, causing an infinite loop.
Solution: Either use left < right
with right = mid
, or use left <= right
with right = mid - 1
.
3. Integer Overflow in Mid Calculation
In languages with fixed integer sizes (like Java or C++), calculating mid = (left + right) / 2
can cause integer overflow when left + right
exceeds the maximum integer value.
Safe Calculation Methods:
# Method 1: Use subtraction to avoid overflow mid = left + (right - left) // 2 # Method 2: Bitwise operation (works in Python) mid = (left + right) >> 1 # Method 3: Python's integer division (no overflow in Python) mid = (left + right) // 2
4. Handling Edge Cases Incorrectly
Failing to handle empty arrays or single-element arrays properly.
Robust Implementation with Edge Case Handling:
def searchInsert(self, nums: List[int], target: int) -> int:
# Handle empty array
if not nums:
return 0
# Standard binary search
left, right = 0, len(nums)
while left < right:
mid = (left + right) >> 1
if nums[mid] >= target:
right = mid
else:
left = mid + 1
return left
Note: The original solution actually handles empty arrays correctly since when nums = []
, left = 0
and right = 0
, so the loop doesn't execute and returns 0, which is correct.
Which data structure is used to implement priority queue?
Recommended Readings
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!