[LeetCode] Search in Rotated Sorted Array

https://leetcode.com/problems/search-in-rotated-sorted-array/

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

solution 1

如果是一个未经旋转的有序数组,显然可以直接用二分查找来做。经过旋转的数组,其实本质就是两个排序数组,我们可以分别在两个数组中进行二分查找,难点是找到两个数组的分界线,用遍历的方式来寻找分界线复杂度为o(n),显然不是我们期待的solution,其实只要意识到整个数组最左边与最右边两个值的特殊性,我们同样可以使用二分的方式来寻找分界线。代码如下:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if (nums.empty()) {
            return -1;
        }
        
        /* without rotating, excute binary search directly */
        int left = 0, right = nums.size() - 1;
        if (nums[left] <= nums[right]) {
            return binarySearch(nums, left, right, target);
        }
        
        /* include two elements at least */
        left = determineBoundary(nums);
        right = left + 1;
        if (nums[0] <= target && target <= nums[left]) {
            return binarySearch(nums, 0, left, target);
        } else if (nums[right] <= target && target <= nums[nums.size() - 1]) {
            return binarySearch(nums, right, nums.size() - 1, target);
        } else {
            return -1;
        }
    }
    
private:
    int binarySearch(const vector<int> &nums, const int start, const int end, int target) {
        int left = start, right = end, middle;
        
        while (left + 1 < right) {
            middle = (left + right) >> 1;
            if (target == nums[middle]) {
                return middle;
            } else if (target > nums[middle]) {
                left = middle;
            } else if (target < nums[middle]) {
                right = middle;
            }
        }
        
        if (target == nums[left]) {
            return left;
        }
        
        if (target == nums[right]) {
            return right;
        }
        
        return -1;
    }
    
    int determineBoundary(const vector<int> &nums) {
        int leftValue = nums[0], rightValue = nums[nums.size() - 1];
        int left = 0, right = nums.size() - 1, middle;
        
        while (left + 1 < right) {
            middle = (left + right) >> 1;
            
            if (leftValue < nums[middle]) {
                left = middle;
            }
            
            if (nums[middle] < rightValue) {
                right = middle;
            }
        }
        
        return left;
    }
};

solution 2

以上的方案我们通过寻找两个排序数组的分界线,从而对其分别使用二分查找来完成搜索。实际上,该题不必如此繁琐,我们可以省去寻找分界线的步骤,直接进行二分查找。代码如下:

// author: Jian-xin Zhou

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if (nums.empty()) {
            return -1;
        }
        
        int left = 0, right = nums.size() - 1, middle;
        
        while (left + 1 < right) {
            middle = (left + right) >> 1;
            
            if (target == nums[middle]) {
                return middle;
            }
            
            if (nums[left] < nums[middle]) {
                if (nums[left] <= target && target < nums[middle]) {
                    right = middle;
                } else {
                    left = middle;
                }
            }
            
            if (nums[middle] < nums[right]) {
                if (nums[middle] < target && target <= nums[right]) {
                    left = middle;
                } else {
                    right = middle;
                }
            }
        }
        
        if (target == nums[left]) {
            return left;
        }
        
        if (target == nums[right]) {
            return right;
        }
        
        return -1;
    }
};
posted @ 2015-05-22 17:03  Acjx  阅读(288)  评论(0编辑  收藏  举报