Searching & SortingProblem 1 of 36
Find first and last positions of an element in a sorted array
Problem Statement
Given a sorted array of integers and a target value, find the starting and ending position of the target value in the array. If the target is not found, return [-1, -1].
Constraints:
- Array is sorted in non-decreasing order
- Target may appear multiple times or not at all
Example:
- Input:
nums = [5, 7, 7, 8, 8, 10],target = 8 - Output:
[3, 4] - Explanation: 8 first appears at index 3 and last appears at index 4
Example 2:
- Input:
nums = [5, 7, 7, 8, 8, 10],target = 6 - Output:
[-1, -1] - Explanation: 6 is not present in the array
Approach 1: Brute Force (Linear Scan)
Intuition
Scan through the entire array to find the first and last occurrence of the target element.
Algorithm
- Initialize first = -1 and last = -1
- Traverse the array from left to right
- When target is found for the first time, set first = current index
- Keep updating last whenever target is found
- Return [first, last]
java
public class Solution {
public int[] searchRange(int[] nums, int target) {
int first = -1, last = -1;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == target) {
if (first == -1) {
first = i;
}
last = i;
}
}
return new int[]{first, last};
}
}Complexity Analysis
- Time Complexity: O(n) - Single pass through the array
- Space Complexity: O(1) - Only using two variables
Approach 2: Binary Search (Optimal)
Intuition
Since the array is sorted, we can use binary search to find the first and last positions efficiently. We perform two binary searches: one to find the leftmost (first) occurrence and another to find the rightmost (last) occurrence.
Algorithm
-
Find First Position:
- Binary search but continue searching left even when target is found
- Update result and search in left half when target is found
-
Find Last Position:
- Binary search but continue searching right even when target is found
- Update result and search in right half when target is found
java
public class Solution {
private int findFirst(int[] nums, int target) {
int left = 0, right = nums.length - 1;
int first = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
first = mid;
right = mid - 1; // Continue searching left
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return first;
}
private int findLast(int[] nums, int target) {
int left = 0, right = nums.length - 1;
int last = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
last = mid;
left = mid + 1; // Continue searching right
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return last;
}
public int[] searchRange(int[] nums, int target) {
return new int[]{findFirst(nums, target), findLast(nums, target)};
}
}Dry Run Example
nums = [5, 7, 7, 8, 8, 10], target = 8
Finding First Position:
left=0, right=5, mid=2, nums[2]=7 < 8 → left=3
left=3, right=5, mid=4, nums[4]=8 == 8 → first=4, right=3
left=3, right=3, mid=3, nums[3]=8 == 8 → first=3, right=2
left=3, right=2 → STOP
First position: 3
Finding Last Position:
left=0, right=5, mid=2, nums[2]=7 < 8 → left=3
left=3, right=5, mid=4, nums[4]=8 == 8 → last=4, left=5
left=5, right=5, mid=5, nums[5]=10 > 8 → right=4
left=5, right=4 → STOP
Last position: 4
Result: [3, 4]
Complexity Analysis
- Time Complexity: O(log n) - Two binary searches
- Space Complexity: O(1) - Only using pointers
Using STL/Built-in Functions
Key Takeaways
- Binary Search Variations: This problem demonstrates how to modify binary search to find boundaries instead of just presence
- Lower Bound vs Upper Bound: Understanding the difference helps in many range-based problems
- Continue Searching: Key insight is to not stop when target is found, but continue in the appropriate direction
- Two Searches: Separate searches for first and last positions keeps the logic clean and easy to understand
- Edge Cases: Handle empty arrays and targets not present in the array
- STL Functions:
lower_boundandupper_boundin C++ provide this functionality built-in