Cracking The Coding Interview Together – Problem 10.3: Search in Rotated Array

Cracking The Coding Interview Together – Problem 10.3: Search in Rotated Array
Photo by Domaintechnik / Unsplash

Picture this: You are tuning a high-throughput microservice that caches configuration routing tables. These tables are strictly sorted by priority keys. However, during an automated failover recovery sequence, the orchestration engine performs a circular shift on the cache entries to prioritize newly elected nodes, leaving your once-pristine sorted array rotated by an unknown offset. Now, your lookup latency SLAs demand a sub-linear search time, but your standard binary search is completely blind-sided by the rotation boundary. How do we find our target key without dropping back to a brute-force linear scan? Today, we are going to unpack Problem 10.3: Search in Rotated Array from Cracking the Coding Interview. By the end of this post, we will build a robust, production-grade algorithm that conquers this data structure challenge with logarithmic efficiency.

Problem Statement

Given a sorted array of n integers that has been rotated an unknown number of times, write code to find the index of a given element in the array. You may assume that the array was originally sorted in increasing order (e.g., [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14] searched for 5 should return index 8).

Our operational goals are clear:

  • Handle duplicate elements gracefully if they exist, or understand how they degrade our performance guarantees.
  • Achieve an optimal time complexity—ideally $O(\log n)$ in the average case.
  • Keep space complexity at $O(1)$ by avoiding unnecessary allocations.

Analyze the Problem Together

Let us break down the constraints and hunt for the "Aha!" conflict. If we look at a standard sorted array like [1, 3, 5, 7, 9, 11], splitting it down the middle gives us two monotonic halves. When we rotate the array—say, moving the last three elements to the front to get [7, 9, 11, 1, 3, 5]—that clean monotonicity shatters.

However, if you pick any arbitrary midpoint in a rotated array, at least one of the two halves must always remain strictly ordered. This is our golden insight! Even though the rotation point breaks global sorting, a local binary split guarantees that one side is a normal, pristine sorted segment while the other side contains the rotation pivot.

Approach Time Complexity Space Complexity Pros & Cons
Linear Scan O(N) O(1) Simple to write, but completely ignores the sorting property. Unacceptable for large datasets.
Find Pivot + Binary Search O(N) or O(log N) O(1) Requires an extra pass to find the minimum element, or complex boundary adjustments.
Modified Binary Search (Our Choice) O(log N) avg O(1) Single-pass elegance. Directly inspects sorted halves and adapts on the fly.

Questions for the Interviewer

Before we drop a single line of code, let's establish our professional engineering posture by asking critical clarifying questions:

  • "Can we assume there are no duplicate values in the array, or do we need to handle duplicates which could force a worst-case $O(N)$ fallback?"
  • "What should the method return if the element is missing? Should we return -1 or throw a custom exception?"
  • "Is the array guaranteed to be rotated, or could it be an unrotated sorted array? Does our solution handle both seamlessly?"

Think About the Solution

Our architecture centers around a modified binary search loop. We maintain left and right pointers. In each iteration:

  1. Calculate mid = left + (right - left) / 2.
  2. Check if array[mid] == target. If yes, return mid.
  3. Determine which half is normally ordered:
    • If array[left] <= array[mid], the left half is sorted.
    • Otherwise, the right half is sorted.
  4. Check if the target falls within the boundaries of the sorted half:
    • If it does, narrow our search range to that sorted half.
    • If it doesn't, search the opposite half.

Edge cases to pre-empt: Empty arrays, arrays with a single element, targets smaller than the minimum or larger than the maximum, and handling arrays with duplicate elements where array[left] == array[mid] == array[right].

Write Code and Explain

Here is our production-ready Java implementation. Notice the defensive checks and clear inline comments explaining each decision.

public class RotatedArraySearch {

    public static int search(int[] arr, int target) {
        if (arr == null || arr.length == 0) {
            return -1;
        }

        int left = 0;
        int right = arr.length - 1;

        while (left <= right) {
            int mid = left + (right - left) / 2;

            // Found our target
            if (arr[mid] == target) {
                return mid;
            }

            // Check if the left half is sorted
            if (arr[left] < arr[mid]) {
                // Does the target lie within the sorted left half?
                if (target >= arr[left] && target < arr[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            } 
            // Otherwise, the right half must be sorted
            else if (arr[left] > arr[mid]) {
                // Does the target lie within the sorted right half?
                if (target > arr[mid] && target <= arr[right]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            } 
            // Handle duplicates where arr[left] == arr[mid]
            else {
                // If left points to the duplicate target, we found it
                if (arr[left] == target) {
                    return left;
                }
                // Otherwise, we cannot be sure which side is sorted, so shrink left
                left++;
            }
        }

        // Target not found
        return -1;
    }

    public static void main(String[] args) {
        int[] rotated = {15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14};
        int target = 5;
        int result = search(rotated, target);
        System.out.println("Element found at index: " + result);
    }
}

Walkthrough of the Code:

  • We initialize left = 0 and right = arr.length - 1.
  • Inside the while loop, we calculate mid safely to prevent integer overflow.
  • We verify if arr[left] < arr[mid]. If true, the left side is cleanly ascending. We then test if our target sits comfortably between arr[left] and arr[mid]. If it does, we discard the right half. If not, we search the right half.
  • If arr[left] > arr[mid], the rotation pivot must reside in the left half, meaning the right half is cleanly sorted. We apply the symmetric boundary check.
  • The else block handles the tricky duplicate edge case (e.g., [2, 2, 2, 3, 2]), incrementing left linearly when ambiguity prevents binary elimination.

Time & Space Complexity

  • Time Complexity: $O(\log n)$ in the average and best case when all elements are distinct. In the absolute worst-case scenario where the array is flooded with duplicate elements (forcing our duplicate fallback to increment left sequentially), the complexity degrades to $O(n)$.
  • Space Complexity: $O(1)$. We only allocate a few primitive integer variables (left, right, mid), maintaining a constant memory footprint regardless of input size.

Why This Problem Matters (The Senior Perspective)

Problems like searching in a rotated array bridge abstract algorithmic theory with real-world systems engineering. Whenever you deal with sharded data stores, consistent hashing rings, or ring buffers in high-performance networking, you encounter data that is logically continuous yet physically wrapped around boundaries. Understanding how to adapt standard divide-and-conquer algorithms to handle structural anomalies without sacrificing performance is a hallmark of senior engineering judgment.

Final Thoughts

Mastering modified binary search unlocks a whole category of interview questions where standard invariants are intentionally broken. Take some time to test this code with edge cases like single-element arrays and heavy duplicates. If you enjoyed this deep dive, share it with a peer or drop a comment below with your favorite binary search variation. Until next time, happy coding!