Find Target in Rotated Sorted Array
You are given an array of length n which was originally sorted in ascending order. It has now been rotated between 1 and n times. For example, the array nums = [1,2,3,4,5,6] might become:
[3,4,5,6,1,2] if it was rotated 4 times.
[1,2,3,4,5,6] if it was rotated 6 times.
Given the rotated sorted array nums and an integer target, return the index of target within nums, or -1 if it is not present.
You may assume all elements in the sorted rotated array nums are unique,
A solution that runs in O(n) time is trivial, can you write an algorithm that runs in O(log n) time?
Example 1:
Input: nums = [3,4,5,6,1,2], target = 1
Output: 4
Example 2:
Input: nums = [3,5,6,0,1,2], target = 4
Output: -1
Constraints:
1 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-1000 <= target <= 1000
Solution
The rotated sorted array can be split into 2 parts: 2 sorted sub-arrays (Property 1) and the minimum number in former array is greater than the maximum number in latter array. (Property 2)
Obviously, to achieve O(logn)O(\log n)O(logn) time complexity we need the power of binary search. However, the rotation breaks the monotony, so how can we solve this?
With property 1, we can know that binary search still works on the single sorted sub-array. Besides, when we look at the process of binary search: we divide the array from the middle. So, at least one side of the divided array is monotonical!
Therefore, all we need to do is to determine which side is monotonical and then determine whether target is in the monotonical interval. If so, the problem evolves back to a normal binary search; if not, we can continue dividing the unordered interval until so.
To determine which side is monotonical, we can use if nums[le] <= nums[mid]
according to property 2, without the worry that interval [le,mid][le, mid][le,mid] is crossing the unordered part.
Code
class Solution:
def search(self, nums: List[int], target: int) -> int:
le = 0
ri = len(nums)-1
while le <= ri:
mid = (le+ri)//2
if nums[mid] == target:
return mid
if nums[le] <= nums[mid]:
if nums[le] <= target < nums[mid]:
ri = mid-1
else:
le = mid+1
else:
if nums[mid] < target <= nums[ri]:
le = mid+1
else:
ri = mid-1
return -1