You are given an integer array nums that was originally sorted in non-decreasing order — but it may contain duplicate values. Before it reaches you, the array is rotated at some unknown pivot index k (0 <= k < nums.length), so it becomes [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]].
For example, [0,1,2,4,4,4,5,6,6,7] rotated at pivot index 5 becomes [4,5,6,6,7,0,1,2,4,4].
Given the rotated array nums and an integer target, return true if target exists in nums, and false otherwise.
A plain linear scan works — but the interviewer wants you to decrease the overall number of operation steps as much as possible. Can you exploit the leftover sorted structure, and can you explain exactly where duplicates hurt you?
1 hiding a single 2, with target = 2. Every probe sees nums[lo] == nums[mid] == nums[hi], so each step can only shrink the range by two — and no algorithm can do better, because the 2 could be at any unexamined position. Duplicates destroy the guarantee, not just this particular algorithm.target may appear many times, so which index to return is ambiguous. Existence is the natural question. (Returning the first occurrence is a good follow-up — it combines this technique with a lower-bound search.)nums[mid] != target is confirmed, and it only fires when nums[lo] and nums[hi] equal nums[mid]. Values already ruled out as the target are always safe to drop.nums[lo] <= nums[mid] always holds and the algorithm behaves as plain binary search on the left-sorted branch.Input: nums = [2,5,6,0,0,1,2], target = 0 Output: true The sorted array [0,0,1,2,2,5,6] was rotated to [2,5,6,0,0,1,2]; 0 appears in it.
Input: nums = [2,5,6,0,0,1,2], target = 3 Output: false 3 does not appear anywhere in the array.
- 1 <= nums.length <= 5000 - -10^4 <= nums[i] <= 10^4 - nums is guaranteed to be rotated at some pivot (possibly pivot 0, leaving it fully sorted) - -10^4 <= target <= 10^4
This problem is the sequel to Search in Rotated Sorted Array — same rotated shelf, one cruel twist: duplicates. That single change breaks a core assumption of the classic solution and teaches you one of binary search's most instructive edge cases: what to do when comparisons stop giving you information.
lo, hi, and mid pointers until it collapses.mid, at least one half is still sorted.O(log n) on typical inputs yet O(n) on adversarial ones.Plain English: the array is a sorted list that got rotated, possibly with repeats. Report whether target is in it — a yes/no answer, not an index (with duplicates, which index would be ambiguous anyway).
Formally: given nums, a non-decreasing array rotated at some pivot k, and an integer target, return true iff some i satisfies nums[i] == target.
Worked example — nums = [2,5,6,0,0,1,2], target = 0
sorted original : [0, 0, 1, 2, 2, 5, 6]
rotated (k = 3) : [2, 5, 6, 0, 0, 1, 2]
└─ larger tail ─┘└ wrapped smaller head
0 appears (twice, even) → true
Asking two or three sharp questions before coding shows you have solved the classic version and know exactly what changed.
“Can the array contain duplicate values?”
Yes — this is the whole problem. With duplicates, comparing the ends to the middle can be inconclusive, and the guaranteed logarithmic bound is lost.
“Is a rotation of zero positions possible, leaving the array fully sorted?”
Yes. Pivot k = 0 reproduces the original array, so your logic must handle a plain sorted array too — classic rotated-search code already does.
“Do I return an index or just whether the target exists?”
Just a boolean. Duplicates make the index ambiguous, so the problem only asks for existence.
“How large can the array be?”
Up to 5000 elements — small enough that O(n) passes, so the real test is whether you can articulate the O(log n) average approach and why the worst case degrades.
Before I code, let me confirm the key difference from the classic rotated-array search: duplicates are allowed here, correct?
Since duplicates make the answer index ambiguous, I will return a boolean for existence rather than a position.
I will binary-search the sorted half as usual, and when the endpoints equal the middle I will shrink both ends by one — which is why the worst case degrades from logarithmic to linear.
Cut a rotated sorted array anywhere: the rotation point falls on one side of mid, so the other side is a clean ascending run. If nums[lo] <= nums[mid], the left half [lo..mid] is sorted; otherwise the right half [mid..hi] is. Once you know which half is sorted, one range check — is target inside that half's endpoints? — tells you which half to keep.
[2, 5, 6, 0, 0, 1, 2] lo=0, mid=3, hi=6 └─sorted?─┘ nums[lo]=2 > nums[mid]=0 → left is NOT sorted → right half [0,0,1,2] is
The rule above needs nums[lo] <= nums[mid] to mean something. Consider [1, 0, 1, 1, 1] with mid = 2: here nums[lo] == nums[mid] == nums[hi] == 1. The left half looks sorted (1 <= 1) but is not — 0 hides inside it. When all three probes are equal, the comparison carries zero information: the target could be hiding in either half.
Suppose nums[lo] == nums[mid] == nums[hi] and we already checked nums[mid] != target. Then nums[lo] != target and nums[hi] != target either — so discarding one element from each end (lo++, hi--) can never throw away the target. It only costs progress: each tie shrinks the range by 2 instead of halving it. That is precisely why an adversarial input like [1,1,1,1,...,1] hiding a single 2 forces O(n) — no algorithm can beat that, because any unexamined position could hold the answer.
| Brute force | Optimal | |
|---|---|---|
| Time | O(n) always | O(log n) average, O(n) worst |
| Space | O(1) | O(1) |
| Idea | Scan every element | Binary search the sorted half; shrink both ends on ties |
Full, runnable code for both approaches lives in the Approaches selector below.
Key takeaway
Rotated-array binary search survives duplicates with one extra rule: when nums[lo] == nums[mid] == nums[hi], shrink both ends and retry — the comparison gave no information, and equal, already-rejected values are safe to drop. The pattern degrade gracefully when a probe is inconclusive reappears in Find Minimum in Rotated Sorted Array II.
lo, hi = 0, n-1
while lo <= hi:
mid = (lo + hi) / 2
if nums[mid] == target: return true
if nums[lo] == nums[mid] == nums[hi]: lo++, hi-- # tie: no info
else if nums[lo] <= nums[mid]: # left half sorted
keep left if nums[lo] <= target < nums[mid], else right
else: # right half sorted
keep right if nums[mid] < target <= nums[hi], else left
return false