← Back to DevBytes

Search in Rotated Array: Multiple Solutions and Complexity Analysis

Search in Rotated Sorted Array: Multiple Solutions and Complexity Analysis

Searching in a rotated sorted array is one of the most classic algorithmic interview problems. It tests your understanding of binary search, array manipulation, and edge-case reasoning. In this tutorial, we will explore what a rotated sorted array is, why this problem matters, and walk through multiple solutions with detailed complexity analysis.

What Is a Rotated Sorted Array?

A rotated sorted array is an array that was originally sorted in ascending order but has been "rotated" at some pivot point. For example, if you take the sorted array [0, 1, 2, 3, 4, 5, 6, 7] and rotate it at index 3, you get [3, 4, 5, 6, 7, 0, 1, 2]. The rotation shifts elements from one end to the other while preserving the relative order within each segment.

The challenge is to find a target element in this rotated array efficiently. A naive linear scan would work in O(n) time, but the goal is to leverage the partial ordering to achieve O(log n) time using a modified binary search.

Why This Problem Matters

This problem is important for several reasons:

Problem Statement

Given a rotated sorted array of distinct integers and a target value, return the index of the target if it exists in the array, otherwise return -1. The algorithm should run in O(log n) time.

Solution 1: Find Pivot Then Binary Search

The first approach breaks the problem into two steps: first, find the pivot index where the rotation occurs, then perform a standard binary search on the appropriate half of the array.

Step 1: Finding the Pivot

The pivot is the smallest element in the array, which is also the point where the array transitions from the larger segment to the smaller segment. We can find it using binary search by comparing the middle element with the rightmost element.

def find_pivot(nums):
    left, right = 0, len(nums) - 1
    while left < right:
        mid = (left + right) // 2
        if nums[mid] > nums[right]:
            left = mid + 1
        else:
            right = mid
    return left

Step 2: Binary Search on the Correct Half

Once we know the pivot, we can determine which half of the array the target lies in by comparing the target with the first and last elements. Then we perform a standard binary search on that segment.

def search_rotated(nums, target):
    if not nums:
        return -1
    
    pivot = find_pivot(nums)
    n = len(nums)
    
    # Decide which half to search
    if target >= nums[0]:
        # Search left portion (0 to pivot-1)
        left, right = 0, pivot - 1
    else:
        # Search right portion (pivot to n-1)
        left, right = pivot, n - 1
    
    while left <= right:
        mid = (left + right) // 2
        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    
    return -1

Complexity Analysis

This two-step approach runs two binary searches sequentially. Finding the pivot takes O(log n) time, and the subsequent binary search also takes O(log n) time. The total time complexity is O(log n), and the space complexity is O(1) since we only use a few variables.

One edge case to consider: when the array is not rotated at all (pivot is 0), the condition target >= nums[0] still works correctly because the entire array is sorted and the left portion covers the whole array.

Solution 2: Single-Pass Modified Binary Search

The second approach is more elegant: it combines both steps into a single binary search. The key insight is that in a rotated sorted array, at least one half of the array (either the left half or the right half of the midpoint) is always properly sorted. We can determine which half is sorted and then decide whether the target lies within that sorted half.

The Algorithm

At each step, compare the middle element with the leftmost element to determine which half is sorted. Then check if the target falls within the range of the sorted half. If it does, search that half; otherwise, search the other half.

def search_rotated_single_pass(nums, target):
    left, right = 0, len(nums) - 1
    
    while left <= right:
        mid = (left + right) // 2
        
        if nums[mid] == target:
            return mid
        
        # Check if the left half is sorted
        if nums[left] <= nums[mid]:
            # Target is in the sorted left half
            if nums[left] <= target < nums[mid]:
                right = mid - 1
            else:
                left = mid + 1
        else:
            # Right half is sorted
            if nums[mid] < target <= nums[right]:
                left = mid + 1
            else:
                right = mid - 1
    
    return -1

How It Works

Let us trace through an example. Consider the array [4, 5, 6, 7, 0, 1, 2] with target 0:

Complexity Analysis

This single-pass solution performs one binary search, giving a time complexity of O(log n) and a space complexity of O(1). It is more efficient in practice than the two-step approach because it halves the search space in every iteration without the overhead of a separate pivot-finding pass.

Solution 3: Recursive Approach

For completeness, here is a recursive implementation of the single-pass modified binary search. The logic is identical, but the structure may appeal to developers who prefer recursive solutions.

def search_rotated_recursive(nums, target):
    def helper(left, right):
        if left > right:
            return -1
        
        mid = (left + right) // 2
        if nums[mid] == target:
            return mid
        
        if nums[left] <= nums[mid]:
            if nums[left] <= target < nums[mid]:
                return helper(left, mid - 1)
            else:
                return helper(mid + 1, right)
        else:
            if nums[mid] < target <= nums[right]:
                return helper(mid + 1, right)
            else:
                return helper(left, mid - 1)
    
    return helper(0, len(nums) - 1)

Complexity Analysis

The recursive solution has the same O(log n) time complexity. However, the space complexity is O(log n) due to the recursion stack, which grows proportionally to the depth of the recursive calls. In production environments with very large arrays, this could lead to stack overflow errors, making the iterative approach preferable.

Solution 4: Handling Duplicates

A common variant of this problem allows duplicate values in the array. This complicates the search because when nums[left] == nums[mid] == nums[right], we cannot determine which half is sorted. The solution is to shrink the search range by moving both pointers inward until we can make a determination.

def search_rotated_with_duplicates(nums, target):
    left, right = 0, len(nums) - 1
    
    while left <= right:
        mid = (left + right) // 2
        
        if nums[mid] == target:
            return True
        
        # When we cannot determine the sorted half
        if nums[left] == nums[mid] == nums[right]:
            left += 1
            right -= 1
        elif nums[left] <= nums[mid]:
            if nums[left] <= target < nums[mid]:
                right = mid - 1
            else:
                left = mid + 1
        else:
            if nums[mid] < target <= nums[right]:
                left = mid + 1
            else:
                right = mid - 1
    
    return False

Complexity Analysis with Duplicates

In the worst case, when all elements are the same except one, the algorithm degrades to O(n) time complexity because we may need to skip duplicates one by one. The space complexity remains O(1). This is an important distinction from the distinct-elements version, which guarantees O(log n) time.

Best Practices

When implementing search in a rotated sorted array, keep the following best practices in mind:

Performance Comparison

Here is a summary of the different solutions and their complexities:

| Solution                    | Time Complexity | Space Complexity | Notes                              |
|-----------------------------|-----------------|------------------|------------------------------------|
| Find pivot + binary search  | O(log n)        | O(1)             | Two passes, conceptually simpler   |
| Single-pass iterative       | O(log n)        | O(1)             | Most efficient, recommended        |
| Recursive                   | O(log n)        | O(log n)         | Stack overhead, risk of overflow   |
| With duplicates             | O(n) worst case | O(1)             | Degrades when many duplicates      |

Conclusion

Searching in a rotated sorted array is a powerful problem that deepens your understanding of binary search and adaptive algorithms. The single-pass iterative solution is the most practical choice, offering optimal O(log n) time and O(1) space complexity while handling all edge cases cleanly. When duplicates are involved, the algorithm must gracefully degrade, and understanding why this happens is just as important as knowing the solution itself. By mastering these techniques, you not only prepare yourself for technical interviews but also build a foundation for solving more complex search and partitioning problems in real-world applications.

— Ad —

Google AdSense will appear here after approval

← Back to all articles