leetcode第32题--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.

题目意思是,原先排好序的,然后右移一定位数,在变换后的array中找到给定值改变之后的下标。如果直接扫描一次的话也能Accept,这就失去了出题的意义。题目是想让我们用二分法。在O(logn)的复杂度下实现,而非n复杂度。

这个人解释的不错如下(先陈述他的解释和代码,我之后再给修正):

下面是rotate后的一个有序数组的图。四边形的斜边表示数组中数值的大小。

在这种情况下数组分了两部分,分别都是有序(递增)的。

当我们计算了Mid以后,有两种可能,分别用Mid1和Mid2表示。

1. 如果A[Low] < A[Mid],说明Mid落在区间1中,即图中Mid1的位置。那么,如果target小于A[Mid1],那么继续在Low和Mid1中间搜索;否则,在Mid1和High中间搜索;

2. 如果A[Low] >= A[Mid],说明Mid落在区间2中,即图中Mid2的位置。同理,如果target小于A[Mid2],那么继续在Low和Mid2中间搜索;否则,在Mid2和High中间搜索。

这样,平均地,我们每次剔除一半数据,时间复杂度是O(logn)。

代码如下:

private static int search2(int[] A, int target){
        int lo = 0;
        int hi = A.length - 1;
        while(lo <= hi){
            int mid = lo + (hi - lo)/2;
            if(target == A[mid]) return mid;
            if(A[mid] > A[lo]){ // 他先判断mid和最左边的值
                if(target >= A[lo] && target < A[mid]){
                    hi = mid - 1;
                }else {
                    lo = mid + 1;
                }
            }else {
                if(target <= A[hi] && target > A[mid]){
                    lo = mid + 1;
                }else {
                    hi = mid -1;
                }
            }
        }
        return -1;
    }

上述是java的代码。他是先判断A[mid]和最左边的大小,这个时候如果例子是[3,1],要找的target是1,那么就会出现问题。因为先判断左边的时候,此时mid和l下标都是0,且值3大于目标,这时判断A[mid] > A[l]不成立,所以认为要在右边找。但是这是虽然target<=A[hi]成立,但是target>A[mid]不成立,因为此时A[mid]为3大于1.所以执行hi = mid -1;这时就巧妙的错过了正确的答案1.导致输出-1.

考虑到这样的case情况,如果先考虑A[mid]和最右边的大小,就可以通过。

class Solution {
public:
    int search(int A[], int n, int target) 
    {
        int l = 0, r = n - 1;

        while(l <= r)
        {
            int mid = (l + r)/2;
            if (A[mid] == target)
                return mid;
            if (A[mid] < A[r]) //先考虑和右边的比较
            {
                if (A[mid] < target && A[r] >= target)
                    l = mid + 1;
                else
                    r = mid - 1;
            }
            else
            {
                if (A[mid] > target && A[l] <= target)
                    r = mid - 1;
                else
                    l = mid + 1;
            }
        }
        return -1;
    }
};

如果确实要从左边开始的话也行,那就是利用比值的时候和mid+或者-1的值去比而不是直接和mid比,因为mid已经判断过是不是等于target了。这样也可以避免之前出现的错误。代码如下:

int search(int A[], int n, int target) {
        int lo = 0;
        int hi = n - 1;
        while(lo <= hi){
            int mid = lo + (hi - lo)/2;
            if(target == A[mid]) return mid;
            if(A[mid] > A[lo]){
                if(target >= A[lo] && target <= A[mid-1]){ // mid-1 的话就是小于等于了
                    hi = mid - 1;
                }else {
                    lo = mid + 1;
                }
            }else {
                if(target <= A[hi] && target >= A[mid+1]){
                    lo = mid + 1;
                }else {
                    hi = mid -1;
                }
            }
        }
        return -1;
    }

 

 2015/03/29: Python

class Solution:
    # @param A, a list of integers
    # @param target, an integer to be searched
    # @return an integer
    def search(self, A, target):
        left, right = 0, len(A)-1
        while left <= right:
            mid = (left + right) / 2
            if A[mid] == target:
                return mid
            if A[mid] < A[right]:
                if A[mid] < target and target <= A[right]:
                    left = mid + 1
                else:
                    right = mid -1
            else:
                if A[mid] > target and target >= A[left]:
                    right = mid - 1
                else:
                    left = mid + 1
        return -1

 

posted on 2014-10-23 20:07  higerzhang  阅读(428)  评论(1编辑  收藏  举报