LeetCode(33)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.

分析如下:

首先注意本题说明了元素是没有重复的。没有重复这个条件非常重要,如果有重复,下面的判断语句就会改写。
参考了一下官网,本题其实是二分查找的变型。
第一种思路,找寻pivot,然后分段进行二分查找,麻烦。
第二种思路,直接进行二分查找,需要比普通的二分查找多写一些判断条件。无需找寻pivot。接下来使用这种做法。
第二种思路的具体分析如下:
求mid,得到A[mid]取值。
如果A[mid]==target,直接返回mid。
否则,如果A[mid]>A[l],说明mid左侧不包含pivot,mid左侧单调递增。
如果target取值范围在左侧,则在左侧进行搜索。
反之,在右侧进行搜索。
否则,说明mid左侧包含pivot,mid右侧单调递增。
如果target取值范围再右侧,则在右侧进行搜索。
反之,在左侧进行搜索。

走完(l<=r)的循环依然没有找到target,则返回-1。

我的代码:

//40ms过大集合
class Solution {
public:
    int search(int A[], int n, int target) {
        int l=0;
        int r=n-1;
        while(l<=r){ // 注意是while(l<=r),不是while(l<r),否则{1}中找1测试失败。
            int mid=l+(r-l)/2;
            if(A[mid]==target){
                return mid;
            }else if(A[mid]>=A[l]){ //注意是A[mid]>=A[l]不是,A[mid]>A[l],理由和上面同理。最后只有1个元素或者2个元素时,mid和l重合。
                if(target<A[mid]&&target>=A[l])
                    r=mid-1;
                else
                    l=mid+1;
            }else {
                if(target<=A[r]&&target>A[mid])
                    l=mid+1;
                else
                    r=mid-1;
            }
        }
        return -1; //循环全部跑完依然找不到就return -1。
    }
};

小结:

(1) 看到leetcode官网上还介绍了一个相关问题,找寻pivot,也就是去找寻最小的元素。思路和上面的相似,代码如下。

注意比较有意思的是,这里的while()条件是 while(A[L]>A[R]),而不是上面的while(L<R)。为什么呢?因为要找寻pivot,就需要让L一直在pivot左边的区域运动,R一直在pivot右边的区域运动,并且,在运动过程中,L和R都不断地向pitvot靠拢,最后临界状态就是L=pivot。这个过程中,当然也满足while(L<R)的条件,但是while(L<R)的条件带来的限制比较弱,可能L和R都在pivot左边,也能够满足L<R。本题是需要找到pivot,所以需要一个比上面更强的限制条件。

int FindSortedArrayRotation(int A[], int N) 
  int L = 0;
  int R = N - 1;
  while (A[L] > A[R]) {
    int M = L + (R - L) / 2;
    if (A[M] > A[R])
      L = M + 1;
    else
      R = M;
  }
  return L;
}

 

参考资料:

(1) http://leetcode.com/2010/04/searching-element-in-rotated-array.html


update : 2015-01-02

写了个递归版本,非常好理解,直接看下面的注释就可以理解。但是带来的tradeoff是,交了几次都是64ms,比上面的40ms的版本慢。后来发现还是比较山寨的,虽然也正确但是不是最快的。

//64ms 较好理解但是比较山寨
class Solution {
public:
    int search(int A[], int target, int start, int end) {
        int mid = start + (end - start) / 2; 
        if (start > end) return -1; //找不到target
        if (A[mid] == target) return mid; //找到target直接返回
        if ((A[mid] > A[end] ) && (target > A[mid])) { //pivot在mid右侧。
        //情况1,如果target比mid大,target一定在mid右侧。
        //情况2,如果target比mid小,target可能在mid左侧或者右侧,因此此时target可为mid之外的任何一个。
            return search(A, target, mid + 1, end);
        } else if ((A[mid] < A[start]) && (target < A[mid])) { //pivot在mid左侧,情况2种,分析类比上面
            return search(A, target, start, mid - 1);
        } else {
        //上面两种情况2, target可能是除了mid之外的任何一个位置。
            int a = search(A, target, start, mid - 1);
            int b = search(A, target, mid + 1, end);
            if (a == -1) return b;
            if (b == -1) return a;
            return a; //或者return b
        }
        
    }
    int search(int A[], int n, int target) {
        return search (A, target, 0, n - 1);
    }
};


如果要更快,还是应该采取上面的官网的做法,水中的鱼这篇blog对这个解法写得非常详细好懂。

自己写了写

//40ms
class Solution {
public:
    int search(int A[], int n, int target) {
        int start = 0, end = n - 1, mid = -1;
        while (start <= end) {
            mid = start + (end - start) / 2;
            if(A[mid] == target) return mid;
            if (A[mid] >= A[start]) {
                if (target >= A[start] && target < A[mid]) 
                //NOTE1:是target >= A[start] 而不是 target > A[start], 是 target < A[mid] 而不是 target <= A[mid];
                //这里的两个边界条件是不统一的。
                    end = mid - 1;
                else 
                    start = mid + 1;
            } else {
                if (target <= A[end] && target > A[mid]) // NOTE2: 同NOTE1
                    start = mid + 1;
                else
                    end = mid - 1;
            }
        }
        return -1;
    }
};

本题有 续集


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值