const solve = (nums) => { let left = 0, right = nums.length - 1; while (left < right) { const sum = nums[left] + nums[right]; if (sum === target) return [left, right]; }}
Problem Walkthrough

Find First and Last Position of Element in Sorted Array

LeetCode 34 teaches you both bisect_left and bisect_right in a single problem — the two boundary binary searches that appear everywhere in interviews.

8 min read|

Two binary searches, two boundaries, one essential pattern

Lower bound and upper bound — the binary search variants behind bisect_left and bisect_right

Find First and Last Position LeetCode — The Boundary Binary Searches

Find First and Last Position of Element in Sorted Array (#34) is one of the most important binary search problems on LeetCode. It teaches you two distinct variants of binary search — finding the leftmost occurrence and the rightmost occurrence of a target value — in a single problem.

These two variants are exactly what Python's bisect_left and bisect_right implement under the hood. Once you internalize them, you can solve any "find the boundary" binary search problem on LeetCode without hesitation.

The problem is rated Medium, but the concept it teaches is foundational. If you can solve this problem cleanly, you have the binary search boundaries pattern locked in for interviews.

Understanding the Problem

You are given a sorted array of integers nums and a target value. Find the starting and ending position of the target in the array. If the target is not found, return [-1, -1]. The solution must run in O(log n) time.

For example, given nums = [5,7,7,8,8,10] and target = 8, the output is [3,4] because the first 8 is at index 3 and the last 8 is at index 4. If target = 6, the output is [-1,-1].

The O(log n) requirement rules out linear scan. You cannot simply walk through the array checking each element. You need binary search — but standard binary search finds any occurrence, not the first or last.

Two Binary Searches — The Core Approach

The key insight for this leetcode 34 solution is to run two separate binary searches: one that finds the leftmost (first) occurrence and one that finds the rightmost (last) occurrence. Each is a small modification of standard binary search.

In standard binary search, when nums[mid] equals the target, you return immediately. For boundary searches, when you find the target, you do not return. Instead, you record it as a candidate and keep searching in one direction to find the true boundary.

This gives you two clean functions: findFirst and findLast. Both run in O(log n), so the total time complexity remains O(log n). The space complexity is O(1) since you only use a few pointer variables.

  • findFirst: Binary search that keeps pushing right boundary left when target is found
  • findLast: Binary search that keeps pushing left boundary right when target is found
  • Total complexity: O(log n) time, O(1) space — two binary searches are still O(log n)
💡

Key Insight

The key difference from standard binary search: when you find the target, DON'T return immediately. Keep searching left (for first) or right (for last). The target match is a candidate, not the answer.

Finding the Leftmost Occurrence — Lower Bound

To find the first occurrence of the target, start with left = 0 and right = nums.length - 1. When nums[mid] equals the target, do not return. Instead, set right = mid - 1 to keep searching the left half. This pushes the search window leftward to find the earliest index.

If nums[mid] is less than the target, set left = mid + 1 as in normal binary search. If nums[mid] is greater than the target, set right = mid - 1. The only change from standard binary search is the behavior when nums[mid] equals the target.

When the loop ends, left will point to the first occurrence of the target — if the target exists. You need to check that left is within bounds and nums[left] actually equals the target before returning it.

  1. 1Initialize left = 0, right = nums.length - 1, result = -1
  2. 2While left <= right: compute mid = left + Math.floor((right - left) / 2)
  3. 3If nums[mid] == target: set result = mid, then right = mid - 1 (keep searching left)
  4. 4If nums[mid] < target: set left = mid + 1
  5. 5If nums[mid] > target: set right = mid - 1
  6. 6Return result (will be -1 if target was never found)

Finding the Rightmost Occurrence — Upper Bound

Finding the last occurrence is the mirror image. When nums[mid] equals the target, set left = mid + 1 instead of returning. This pushes the search window rightward to find the latest index where the target appears.

Everything else stays the same. Less than target means search right, greater means search left. The only behavioral change is what happens on equality — you keep going right instead of stopping or going left.

After the loop, your recorded result holds the rightmost index of the target. Together with the leftmost search, you have the complete binary search range that solves the find first and last position leetcode problem.

⚠️

Validation Required

After finding the leftmost position, verify that nums[left] == target — if the target doesn't exist, the binary search will converge to a wrong position. Always validate.

Edge Cases to Handle

Several edge cases can trip you up in interviews. An empty array should immediately return [-1,-1]. A single-element array where that element is the target returns [0,0]. If the target is smaller than all elements or larger than all elements, both searches will correctly return -1.

When all elements in the array equal the target, your leftmost search returns 0 and your rightmost search returns nums.length - 1. This case naturally works if your binary search boundaries are correct.

Target at the boundaries of the array (first or last element) also works correctly because the binary search narrows to that position. The key is that your result variable captures any match before the search window narrows further.

  • Empty array: return [-1,-1] immediately
  • Single element equal to target: return [0,0]
  • All elements equal to target: returns [0, length-1]
  • Target not present: both searches return -1
  • Target at array boundaries: handled naturally by the search

What Find First and Last Position Teaches You

This problem is the foundation for all binary search boundaries problems on LeetCode. The lower bound and upper bound pattern appears in Search Insert Position (#35), First Bad Version (#278), Find Minimum in Rotated Sorted Array (#153), and many more.

Once you can write both findFirst and findLast from memory, you have a template that applies to dozens of binary search problems. The pattern is always the same: instead of returning when you find a match, record it and keep narrowing.

Binary search boundaries are one of the most tested patterns in coding interviews at top tech companies. Practice this problem until the two variants feel automatic, then drill the pattern with YeetCode flashcards to lock it into long-term memory.

  • Lower bound (bisect_left): find the first position where target could be inserted
  • Upper bound (bisect_right): find the position just after the last occurrence
  • Template applies to: Search Insert Position, First Bad Version, Find Peak Element, and more
  • Complexity: always O(log n) time, O(1) space
ℹ️

Why This Problem Matters

Find First and Last Position (#34) is the problem that teaches bisect_left and bisect_right — the two binary search variants that Python's bisect module implements.

Ready to master algorithm patterns?

YeetCode flashcards help you build pattern recognition through active recall and spaced repetition.

Start practicing now