Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

1.16 Search In Rotated Sorted Array II

Source: src/main/kotlin/binarysearch/SearchInRotatedArray_II.kt Pattern: rotated binary search with duplicates · Core page

The Problem

Search in a rotated array that may contain duplicates (return existence).

  • Constraints: n ≤ 5000.

Examples

Input:  nums = [2,5,6,0,0,1,2], target = 0   -> Output: true
Input:  nums = [2,5,6,0,0,1,2], target = 3   -> Output: false

Intuition — the rotated search; when nums[mid] == nums[left], shrink

Duplicates break the rotation detection: nums[left] == nums[mid] can’t tell which side is sorted. The fix: narrow the range (left++) and retry:

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

    when {
        nums[mid] == target -> return true
        nums[left] == nums[mid] -> left++      // ambiguous: shrink
        nums[left] < nums[mid] -> {            // left half sorted
            if (target in nums[left]..nums[mid]) right = mid - 1
            else left = mid + 1
        }
        else -> {                              // right half sorted
            if (target in nums[mid]..nums[right]) left = mid + 1
            else right = mid - 1
        }
    }
}
return false

Why left++ on the tie? Equal endpoints make both halves “look sorted” ambiguously — advancing one step removes a duplicate and re-tests. Worst case degrades to O(n) (all duplicates), but typical stays O(log n).

Approach 1 — Binary search with ambiguity shrink (the repo’s version, optimal)

class SearchInRotatedArray_II {
    /**
     * @param nums   rotated sorted array with duplicates
     * @param target search value
     * @return       true iff found
     */
    fun search(nums: IntArray, target: Int): Boolean {
        var left = 0
        var right = nums.lastIndex

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

            when {
                nums[mid] == target -> return true
                nums[left] == nums[mid] -> left++
                nums[left] < nums[mid] -> {
                    if (target in nums[left]..nums[mid]) right = mid - 1
                    else left = mid + 1
                }
                else -> {
                    if (target in nums[mid]..nums[right]) left = mid + 1
                    else right = mid - 1
                }
            }
        }
        return false
    }
}
public class SearchInRotatedSortedArrayII {
    /**
     * @param nums   rotated sorted array with duplicates
     * @param target search value
     * @return       true iff found
     */
    public boolean search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;

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

            if (nums[mid] == target) return true;

            if (nums[left] == nums[mid]) left++;
            else if (nums[left] < nums[mid]) {
                if (target >= nums[left] && target <= nums[mid]) right = mid - 1;
                else left = mid + 1;
            } else {
                if (target >= nums[mid] && target <= nums[right]) left = mid + 1;
                else right = mid - 1;
            }
        }
        return false;
    }
}
#include <vector>

class SearchInRotatedSortedArrayII {
public:
    /**
     * @param nums   rotated sorted array with duplicates
     * @param target search value
     * @return       true iff found
     */
    bool search(std::vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;

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

            if (nums[mid] == target) return true;

            if (nums[left] == nums[mid]) left++;
            else if (nums[left] < nums[mid]) {
                if (target >= nums[left] && target <= nums[mid]) right = mid - 1;
                else left = mid + 1;
            } else {
                if (target >= nums[mid] && target <= nums[right]) left = mid + 1;
                else right = mid - 1;
            }
        }
        return false;
    }
};
def search(nums: list[int], target: int) -> bool:
    """
    @param nums:   rotated sorted array with duplicates
    @param target: search value
    @return:       true iff found
    """
    left, right = 0, len(nums) - 1

    while left <= right:
        mid = (left + right) // 2

        if nums[mid] == target:
            return True

        if nums[left] == nums[mid]:
            left += 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
#![allow(unused)]
fn main() {
impl Solution {
    /// @param nums   rotated sorted array with duplicates
    /// @param target search value
    /// @return       true iff found
    pub fn search(nums: Vec<i32>, target: i32) -> bool {
        let (mut left, mut right) = (0, nums.len() - 1);

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

            if nums[mid] == target { return true; }

            if nums[left] == nums[mid] { left += 1; }
            else if nums[left] < nums[mid] {
                if target >= nums[left] && target <= nums[mid] { right = mid - 1; }
                else { left = mid + 1; }
            } else {
                if target >= nums[mid] && target <= nums[right] { left = mid + 1; }
                else { right = mid - 1; }
            }
        }
        false
    }
}
}

Dry run

Input: nums = [2,5,6,0,0,1,2], target = 0.

left=0, right=6.  mid=3 (0).  found -> true ✓

Input: [1,0,1,1,1], target = 0: mid=2 (1).  nums[0]==1 == mid -> left=1.
  mid=(1+4)/2=2 (1): nums[1]=0 != 1.  nums[1] < nums[2]: right-half check: 0 in [1..1]? no
  -> right=1.  mid=1 (0): found ✓

Complexity

Time. O(log n) typical, O(n) worst (all duplicates):

$$ T(n) = O(\log n) $$

Space. Constants:

$$ S(n) = O(1) $$

Variants & follow-ups

  • Search In Rotated Sorted Array (1.17) — the no-duplicates sibling.
  • Interview follow-up: “Why can’t duplicates keep it O(log n)?” An adversarial all-equal array forces the left++ shrink to walk linearly — no comparison can distinguish. The problem accepts the O(n) worst case (existence only).