Search in Rotated Sorted Array

Solution

The key is we can see that one half of the array must be ordered normally (in increasing order). We can therefore look at the normally ordered half to determine whether we should search the left or right half.

Time complexity: O(lgN)

Assume no duplicates

public int search(int[] nums, int target) {
    int left = 0, right = nums.length - 1;

    while (left <= right) {
        int mid = (left + right) / 2;
        if (target == nums[mid]) {
            return mid;
        }
        // since 'left' could be equal to 'mid', so we have '<=' instead of '<'
        if (nums[left] <= nums[mid]) { // left half is noramlly ordered
            if (target >= nums[left] && target <= nums[mid]) { // target is in the left half
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        } else { // right half is normally ordered
            if (target >= nums[mid] && target <= nums[right]) { // target is in the right half
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
    }
    return -1;
}

Recursive approach

public int search(int[] nums, int target) {
    return binarySearch(nums, 0, nums.length-1, target);
}

public int binarySearch(int[] nums, int left, int right, int target){
    if(left>right) 
        return -1;

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

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

    if(nums[left] <= nums[mid]){
        if(nums[left]<=target && target<nums[mid]){
          return binarySearch(nums,left, mid-1, target);
        }else{
          return  binarySearch(nums, mid+1, right, target);
        }
    }else {
        if(nums[mid]<target&& target<=nums[right]){
          return  binarySearch(nums,mid+1, right, target);
        }else{
          return  binarySearch(nums, left, mid-1, target);
        }
    }
}

Follow up: what if duplicates exist

The trick condition is the left and the middle are identical.

For example: In array {2, 2, 3, 4, 2}.

In this case, we can check if the rightmost element is different, if it is, we can search just the right side. Otherwise, we have no other choice but to search for both halves.

public int search(int[] nums, int target) {
    return search(nums, 0, nums.length - 1, target);
}

public int search(int[] nums, int left, int right, int x) {
    if (right < left) return -1;
    int mid = (left + right) / 2;

    if (x == nums[mid]) return mid;

    if (nums[left] < nums[mid]) { // left is normally ordered
        if (x >= nums[left] && x <= nums[mid]) { // the target is on the left 
            return search(nums, left, mid - 1, x); // search left
        } else {
            return search(nums, mid + 1, right, x); // search right
        }
    } else if (nums[mid] < nums[left]) {// right is normally ordered
        if (x >= nums[mid] && x <= nums[right]) { // the target is on the right 
            return search(nums, mid + 1, right, x); // search right
        } else {
            return search(nums, left, mid - 1, x); // search left
        }            
    } else if (nums[left] == nums[mid]) { // left half is ALL repeats
        if (nums[mid] != nums[right]) { // if right is diff, search it
            return search(nums, mid + 1, right, x);
        } else { // else we have to search both halves
            int result = search(nums, left, mid - 1, x); // search left first
            if (result == -1) {
                search(nums, mid + 1, right, x); // search right
            } else {
                return result;
            }
        }
    }
    return -1;
}