Searching in a rotated sorted array is a classic algorithmic problem that frequently appears in technical interviews and competitive programming. Also, it tests a developer's ability to adapt the standard binary search algorithm to handle a specific variation of sorted data. Unlike a standard sorted array where elements increase monotonically from left to right, a rotated sorted array has been shifted cyclically, creating two distinct sorted subarrays. Understanding how to manage this structure efficiently—maintaining O(log n) time complexity—is a fundamental skill for any software engineer Most people skip this — try not to..
Understanding the Rotated Sorted Array Structure
Before diving into the search logic, it is crucial to visualize the data structure. Imagine a standard sorted array in ascending order: [0, 1, 2, 4, 5, 6, 7]. If this array is rotated at a pivot index (for example, index 3), the elements after the pivot move to the front. The resulting array becomes [4, 5, 6, 7, 0, 1, 2].
This rotation creates a distinct property: **the array consists of two individually sorted subarrays.Day to day, ** The first subarray (from start to pivot-1) contains the larger elements, and the second subarray (from pivot to end) contains the smaller elements. On the flip side, the pivot point is the only location where the next element is smaller than the current one (e. Even so, g. , 7 followed by 0).
The challenge arises because standard binary search assumes the entire array is ordered. If you pick a middle element in a rotated array, you cannot simply decide to go left or right based on a comparison with the target alone. You must first determine which sorted half the middle element belongs to, and then decide if the target resides in that half.
The Core Logic: Modified Binary Search
The optimal approach modifies the standard binary search template. In practice, the algorithm maintains two pointers, left and right, representing the current search boundaries. In each iteration, it calculates the mid index.
- Check for Direct Hit: If
nums[mid] == target, returnmidimmediately. - Identify the Sorted Half: Compare
nums[left]withnums[mid].- If
nums[left] <= nums[mid], the left half (fromlefttomid) is sorted in ascending order. - Otherwise, the right half (from
midtoright) must be sorted.
- If
- Determine Target Location: Once the sorted half is identified, check if the
targetlies within the range of that sorted half.- If the left half is sorted: Check if
nums[left] <= target < nums[mid]. If true, the target is in the left half; moveright = mid - 1. Otherwise, it must be in the right half; moveleft = mid + 1. - If the right half is sorted: Check if
nums[mid] < target <= nums[right]. If true, the target is in the right half; moveleft = mid + 1. Otherwise, moveright = mid - 1.
- If the left half is sorted: Check if
- Repeat or Exit: Continue the loop while
left <= right. If the loop finishes without finding the target, return-1.
This logic works because at least one half of the array (divided by mid) is always perfectly sorted. In real terms, by identifying that sorted half, we can apply standard binary search range checks on it. If the target isn't there, it must be in the other (rotated) half Small thing, real impact..
Step-by-Step Walkthrough with an Example
Let's trace the algorithm with the array nums = [4, 5, 6, 7, 0, 1, 2] and target = 0.
Initial State: left = 0, right = 6.
Iteration 1:
mid = (0 + 6) // 2 = 3.nums[3] = 7.nums[mid] (7) != target (0).- Check sorted half:
nums[left] (4) <= nums[mid] (7)is True. Left half[4, 5, 6, 7]is sorted. - Check target in left half:
nums[left] (4) <= target (0) < nums[mid] (7)is False (0 is not >= 4). - Action: Target is not in sorted left half. Move
left = mid + 1 = 4.
Iteration 2:
left = 4,right = 6.mid = (4 + 6) // 2 = 5.nums[5] = 1.nums[mid] (1) != target (0).- Check sorted half:
nums[left] (0) <= nums[mid] (1)is True. Left half[0, 1]is sorted. - Check target in left half:
nums[left] (0) <= target (0) < nums[mid] (1)is True. - Action: Target is in sorted left half. Move
right = mid - 1 = 4.
Iteration 3:
left = 4,right = 4.mid = 4.nums[4] = 0.nums[mid] (0) == target (0). Found at index 4.
The algorithm successfully locates the target in logarithmic time, discarding half the search space in every step That alone is useful..
Python Implementation
Here is a clean, production-ready Python implementation of the algorithm described above Worth keeping that in mind..
def search_rotated_array(nums: list[int], target: int) -> int:
"""
Searches for a target value in a rotated sorted array.
Returns the index if found, otherwise -1.
Time Complexity: O(log n)
Space Complexity: O(1)
"""
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
# 1. Direct hit
if nums[mid] == target:
return mid
# 2. In practice, determine which half is properly sorted
if nums[left] <= nums[mid]:
# LEFT HALF IS SORTED: [left ... mid]
if nums[left] <= target < nums[mid]:
# Target lies in the sorted left half
right = mid - 1
else:
# Target lies in the rotated right half
left = mid + 1
else:
# RIGHT HALF IS SORTED: [mid ...
return -1
Handling Edge Cases and Variations
While the core logic handles the standard problem (distinct integers), real-world scenarios and interview follow-ups often introduce variations.
1. Arrays with Duplicates
If the array contains duplicate values (e.g., [2, 2, 2, 3, 4, 2]), the condition nums[left] <= nums[mid] becomes ambiguous. When nums[left] == nums[mid], we cannot definitively say which half is sorted. As an example, in [1, 0, 1, 1, 1], left=0, mid=2, both are 1. The pivot could be on the left or right Still holds up..
Solution: When nums[left] == nums[mid] == nums[right], we cannot decide the sorted half. The standard fix is to shrink the search space linearly: left += 1 and `right -=
1. But for instance, in the array [1, 0, 1, 1, 1]searching for0, the equality of the boundaries obscures the pivot point. Practically speaking, this cautious step is necessary because when nums[left] == nums[mid] == nums[right], we cannot determine which half is sorted. That's why by incrementing leftand decrementingright`, we reduce the search space without risking exclusion of the target. This adjustment ensures correctness at the potential cost of linear time in worst-case duplicate-heavy scenarios, but it remains a strong fallback.
2. Search in a Rotated Sorted Array with No Duplicates
The primary implementation assumes distinct elements, which guarantees that nums[left] <= nums[mid] correctly identifies the sorted half. This version achieves strict O(log n) time complexity and is optimal for arrays without duplicates And it works..
Practical Applications and Why It Matters
The rotated sorted array search is a classic example of how understanding problem structure—here, the rotation pivot—enables efficient algorithms. It appears in real-world systems such as database indexing, where data might be stored in rotated order due to log rotations or circular buffers. Mastering this algorithm strengthens intuition for divide-and-conquer strategies and prepares for advanced variations like finding the pivot index or searching in two-dimensional rotated arrays.
Conclusion
In this article, we dissected the rotated binary search algorithm, illustrating how to identify the sorted half and discard the irrelevant portion of the array in logarithmic time. And we provided a production-ready Python implementation and addressed the critical edge case of duplicates with a linear shrink approach. By grasping these concepts, you are better equipped to tackle similar search problems in rotated or otherwise modified sorted structures, reinforcing the importance of careful invariant maintenance in algorithm design.