1. 题目

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.

2. 思路

先找到最小值的下标,然后根据比较结果判断是哪一段有序数组里进行二分查找。
最小值的查找通过递归进行。对于某一段循环有序数组,二分为两段进行定位查找,前段的尾节点等于后段的首节点,即有一个交叉点,避免漏掉。如果两段都是有序的,说明整体是有序的,返回前段的首节点。如果某一段的首大于尾,则在这一段里面进行递归查找。

3. 代码

class Solution {
public:
    // 先找到最小点,然后在在其中一边做二分查找。
    // 如果是有序的, 则末端大于首端; 基于此可以二分定位到最小点
    int search(vector<int>& nums, int target) {
        int sz = nums.size();
        if (sz == 0) return -1;
        if (sz == 1) return nums[0] == target ? 0 : -1;
        int min_idx = find_min_idx(nums, 0, nums.size());
        //cout << min_idx << " " << nums[min_idx] << endl;
        if (target <= nums[sz-1]) {
            return bsearch(nums, min_idx, sz, target);
        } else {
            return bsearch(nums, 0, min_idx, target);
        }
    }
    
    int find_min_idx(vector<int>& nums, int i, int j) {
        if (i >= j) return -1;
        if (j - i == 1) return i;
        if (j - i == 2) return nums[i] > nums[j-1] ? j-1 : i;
        int k = (i + j) / 2;
        if (nums[k] < nums[i]) {
            return find_min_idx(nums, i, k+1);
        } else if (nums[k] > nums[j-1]) {
            return find_min_idx(nums, k, j);
        } else {
            return i;
        }
    }
    
    int bsearch(vector<int>& nums, int i, int j , int target) {
        if (j <= i) return -1;
        int k = (i + j) / 2;
        if (nums[k] == target) {
            return k;
        } else if (nums[k] > target) {
            return bsearch(nums, i, k, target);
        } else {
            return bsearch(nums, k+1, j, target);
        }
    }
};

knzeus
72 声望28 粉丝

行万里路,读万卷书