Topics
Idea
Few different ways to write the conditions. One simple way is to think as such:
- If target is larger than middle element, it will always be on the right half, unless, it’s also larger than
nums[hi]
, case:[5, 1, 2, 3, 4], target=5
. - Similarly, if target is smaller than middle element, it will always be on the left half, unless, it’s also smaller than
nums[lo]
, case:[3, 4, 5, 1, 2], target=1
Another way is to think in terms of “finding the sorted half”:
- If
nums[mid] <= nums[hi]
, then the right half is sorted. If the target is within this range, we search in the right half (lo = mid + 1
), otherwise, we go left (hi = mid - 1
) - If
nums[mid] >= nums[lo]
, then the left half is sorted. If the target is within this range, we continue on the left (hi = mid - 1
), otherwise, we move to the right (lo = mid + 1
)
Code
# Approach 1
def search(nums, target):
lo = 0
hi = len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] == target:
return mid
elif nums[mid] <= nums[hi] < target:
hi = mid - 1
elif nums[mid] < target:
lo = mid + 1
elif target < nums[lo] <= nums[mid]:
lo = mid + 1
elif target < nums[mid]:
hi = mid - 1
return -1
# Approach 2
def search(nums, target):
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] == target:
return mid
# Determine which half is sorted
if nums[lo] <= nums[mid]: # Left half is sorted
if nums[lo] <= target < nums[mid]:
hi = mid - 1
else:
lo = mid + 1
else: # Right half is sorted
if nums[mid] < target <= nums[hi]:
lo = mid + 1
else:
hi = mid - 1
return -1
now, if there’s a variation: find target in rotated sorted array with duplicates, there can be cases where we can’t figure out which half is “sorted”:
If such a case is encountered in our search space, we do hi--
and lo++
:
if nums[mid] == nums[lo] == nums[hi]:
hi -= 1
lo += 1
Adding above block works for both approaches discussed previously.