81. Search in Rotated Sorted Array II
Problem¶
There is an integer array nums
sorted in non-decreasing order (not necessarily with distinct values).
Before being passed to your function, nums
is rotated at an unknown pivot index k
(0 <= k < nums.length
) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]
(0-indexed). For example, [0,1,2,4,4,4,5,6,6,7]
might be rotated at pivot index 5
and become [4,5,6,6,7,0,1,2,4,4]
.
Given the array nums
after the rotation and an integer target
, return true
if target
is in nums
, or false
if it is not in nums
.
You must decrease the overall operation steps as much as possible.
Example 1:
Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true
Example 2:
Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false
Constraints:
1 <= nums.length <= 5000
-104 <= nums[i] <= 104
nums
is guaranteed to be rotated at some pivot.-104 <= target <= 104
Follow up: This problem is similar to 33. Search in Rotated Sorted Array, but nums
may contain duplicates. Would this affect the runtime complexity? How and why?
Solve¶
Remove Duplicate + Find shift point + Binary search¶
O(n)
Some conclusion¶
While there is a lot of similarity from 33. Search in Rotated Sorted Array . The main breaking point is that we can’t effectively find the shift point as if nums[mid] == nums[0]
, it could either be left, or right because of duplication. Both example could be:
So to preventing this, we should at least remove duplication on either end, here is a snippet code that I try to clear the duplicate on nums
array left side:
for i in range(n-1,-1,-1):
if nums[i] == nums[0]:
continue
self.nums = nums[:i+1]
n = len(self.nums)
break
if n == 0:
return False
Final code should be the same as 33. Search in Rotated Sorted Array
class Solution:
def findShiftPoint(self):
shiftPoint = -1
isFound = False
pointerLeftIndex = 0
pointerRightIndex = len(self.nums)
while True:
midIndex = (pointerLeftIndex + pointerRightIndex) // 2
if pointerLeftIndex == midIndex:
break
if self.nums[midIndex] >= self.nums[0]:
pointerLeftIndex = midIndex
else:
pointerRightIndex = midIndex
if pointerLeftIndex+1 == pointerRightIndex:
shiftPoint = len(self.nums)-1 - pointerLeftIndex
isFound = True
return (shiftPoint, isFound)
def binarySearch(self, startIndex,endIndex, target):
targetIndex, isFound = -1, False
left = startIndex-1
right = endIndex +1
while True:
midIndex = (left + right) // 2
if left == midIndex:
break
if self.nums[midIndex] <= target:
left = midIndex
else:
right = midIndex
if left+1 == right:
targetIndex = left
if startIndex <= targetIndex <= endIndex:
isFound = self.nums[targetIndex] == target
return (targetIndex, isFound)
def search(self, nums: List[int], target: int) -> int:
self.nums = nums
n = len(nums)
self.target = target
for i in range(n-1,-1,-1):
if nums[i] == nums[0]:
continue
self.nums = nums[:i+1]
n = len(self.nums)
break
if n == 0:
return False
result = -1
shiftPoint, isFound = self.findShiftPoint()
targetIndex, isFound = self.binarySearch(0, n- shiftPoint -1, target)
if isFound:
return True
targetIndex, isFound = self.binarySearch(n- shiftPoint,n-1, target)
if isFound:
return True
return False
Time complexity: Worst case O(n)
- As we need to remove duplicate on left/right side, which in theory can be the whole array, costing O(n) time
- Other binary finding cost O(log n)
Created : August 16, 2023