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 Search in Rotated Sorted Array, but nums
may contain duplicates. Would this affect the runtime complexity? How and why?
This problem asks to determine if a target integer exists within a rotated sorted array that may contain duplicate values. The key difference from the problem without duplicates is the handling of duplicate elements, which affects the time complexity.
Approach: Modified Binary Search
The most efficient approach is a modified binary search. A standard binary search wouldn't work directly because the array is rotated. The modification handles the potential for duplicates, which makes it impossible to definitively determine which half of the array to search in certain cases.
Algorithm:
Initialization: Set left
pointer (l) to 0 and right
pointer (r) to the last index of the array.
Iteration: While left
< right
:
mid = (left + right) / 2
.nums[mid] > nums[right]
: This indicates that the right half of the array (mid + 1
to right
) is sorted.
nums[left] <= target <= nums[mid]
, search in the left half (left
to mid
).mid + 1
to right
).nums[mid] < nums[right]
: This implies that the left half of the array (left
to mid
) is sorted.
nums[mid] < target <= nums[right]
, search in the right half (mid + 1
to right
).left
to mid
).nums[mid] == nums[right]
: This is the crucial case handling duplicates. We can't definitively say which half is sorted. In this situation, we simply decrement right
by 1. This is because if nums[mid] == nums[right]
, then the last element can be safely disregarded in the next iteration. The worst-case scenario is where this condition repeats multiple times, leading to a linear time complexity in the worst case.Termination: The loop terminates when left
== right
. At this point, nums[left]
(or nums[right]
) is checked against the target. If they are equal, the target exists in the array; otherwise, it does not.
Time Complexity Analysis:
[2, 2, 2, 2, 2, 2, 2, 2, 0]
. If the target is not 2, the nums[mid] == nums[right]
condition will be met many times in succession, effectively making the search linear. The algorithm may end up checking most or all of the elements in the array.Space Complexity: O(1). The algorithm uses a constant amount of extra space.
Code Examples (Python):
class Solution:
def search(self, nums: List[int], target: int) -> bool:
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) // 2
if nums[mid] == target:
return True
elif nums[mid] > nums[r]: #right half sorted
if nums[l] <= target < nums[mid]:
r = mid - 1
else:
l = mid + 1
elif nums[mid] < nums[r]: #left half sorted
if nums[mid] < target <= nums[r]:
l = mid + 1
else:
r = mid -1
else: #nums[mid] == nums[r] handle duplicates
r -= 1
return False
The provided code in other languages follows the same logic and algorithmic structure. They differ only in syntax and language-specific details.