Description
Given an array of integers nums
sorted in non-decreasing order, find the starting and ending position of a given target
value.
If target
is not found in the array, return [-1, -1]
.
You must write an algorithm with O(log n)
runtime complexity.
Constraints
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
is a non-decreasing array.-109 <= target <= 109
Examples
- Example 1:
Input:nums = [5, 7, 7, 8, 8, 10]
,target = 8
Output:[3, 4]
- Example 2:
Input:nums = [5, 7, 7, 8, 8, 10]
,target = 6
Output:[-1, -1]
- Example 3:
Input:nums = []
,target = 0
Output:[-1, -1]
Solution 1: Brute-Force
Thought
The input parameter nums
has already been sorted in increasing order. Therefore, the most intuitive approach is to iterate through the entire array from both the start and end separately. Record the index of the first occurrence of a value equal to the target from both ends and return these two indices at the end.
Steps
- Initialize two pointers,
i
andj
, starting at0
andlen(nums) - 1
, respectively. - Initialize the variable
positions
as[-1, -1]
to serve as a record for the found index positions. - Start by sequentially iterating through the entire
nums
starting fromi
. Ifnums[i]
is equal to thetarget
, record the current positioni
inpositions[0]
and then break the iteration. - For the second iteration, iterate through
nums
in reverse, starting fromj
. Ifnums[j]
is equal to thetarget
, record the current positionj
inpositions[1]
and then break the iteration. - Finally, return
positions
.
Codes
def search_range(nums: List[int], target: int) -> List[int]:
i = 0
j = len(nums) - 1
positions = [-1, -1]
while i < len(nums):
if nums[i] == target:
positions[0] = i
break
i += 1
while j >= 0:
if nums[j] == target:
positions[1] = j
break
j -= 1
return positions
PythonComplexities
- Time Complexity:
O(N)
, whereN
represents the length ofnums
. - Space Complexity:
O(1)
.
Solution 2: Binary Search
Thought
The prompt mentioning an optimal time complexity of O(log N)
strongly suggests the use of binary search, especially considering the task involves finding a target in a sorted array. We can employ binary search twice successively to approach the closest and farthest targets to obtain the final answer.
Steps
- Initialize the variable
positions
as[-1, -1]
to serve as a record for the found index positions. - The first search:
- Initialize the
left
andright
pointers to0
andlen(nums) - 1
, respectively, to define the search range. - When
left
is less than or equal toright
:- Calculate the
mid
position as(left + right) // 2
. - If
nums[mid]
is less than thetarget
, move theleft
pointerleft
to the positionmid + 1
. - If
nums[mid]
is greater than thetarget
, move theright
pointerright
to the positionmid - 1
. - If
nums[mid]
is equal to thetarget
:- As we’re searching for the first occurrence of the
target
, we need to check if the element beforemid
(nums[mid - 1]
) is also equal to thetarget
. If it is, move theright
pointer to positionmid - 1
and continue the search. - If not, it means we’ve found the position of the first occurrence of the
target
. Record it inpositions[0]
and terminate the search.
- As we’re searching for the first occurrence of the
- Calculate the
- Initialize the
- The second search:
- The search logic is identical to the first search. The only difference is that now we’re searching for the position of the last occurrence of the
target
. Whenmid
points to a position equal to thetarget
and the next position (nums[mid + 1]
) is also equal to thetarget
, move theleft
pointer to positionmid + 1
and continue the search.
- The search logic is identical to the first search. The only difference is that now we’re searching for the position of the last occurrence of the
- Finally, return
positions
.
Codes
def search_range(nums: List[int], target: int) -> List[int]:
positions = [-1, -1]
# find the first position
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
else:
if mid > 0 and nums[mid - 1] == target:
right = mid - 1
else:
positions[0] = mid
break
# find the last position
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
else:
if mid < len(nums) - 1 and nums[mid + 1] == target:
left = mid + 1
else:
positions[1] = mid
break
return positions
PythonComplexities
- Time Complexity:
O(logN)
, whereN
represents the length ofnums
. - Space Complexity:
O(1)
.