旋转有序数组的二分查找

要求

  给定一个没有重复元素的旋转数组(它对应的原数组是有序的),求给定元素在旋转数组内的下标(不存在的返回-1)。

例子

有序数组{0,1,2,3,4,5,6,7}对应的旋转数组为{3,4,5,6,7,0,1,2}(左旋、右旋效果相同)。

  • 查找元素5,返回结果2;
  • 查找元素8,返回结果-1。

分析

  可以轻易地想到遍历一遍O(n)时间可以得到结果,但是并不是最好的结果;利用有序的特点,可以轻易的想到二分查找的方法。经过旋转后的数组总是可以分为两个有序序列,如下图所示。旋转数组分成了红蓝两段有序序列。

                                                            

  可以看出中间位置m(m')的两边必然有一个是有序的,如果是m则左边有序;如果是m'则右边有序;如下可以看出。

                                                            

  总结规律:每次根据L和R求出m后,m左边[L, m-1]和右边[m+1, R]这两部分中至少一个是有序的。

       (1)arr[m]=X,返回m

       (2)arr[m]<arr[R],位于m'位置右侧是有序的;当arr[m']<X<arr[R]时,则L=m'+1,否则R=m'-1。

       (3)arr[m]>=arr[R],位于m位置左侧是有序的;当arr[L]<X<arr[m]时,则R=m-1,否则L=m+1。

参考代码

 数组的旋转点击这里查看。

int BSearch(int *arr, int len, int X){
    int L = 0, R = len - 1;
    int m;
    while (L <= R){                         //循环条件
        m = (L + R) / 2;
        if (arr[m] == X)                    //找到了,终止
            return m;
        if (arr[m] < arr[R]){               //右侧有序
            if (arr[m] < X && arr[R] >= X){ 
                L = m + 1;
            }
            else
                R = m - 1;
        }
        else{                               //左侧有序
            if (arr[m] > X && arr[L] <= X){
                R = m - 1;
            }
            else
                L = m + 1;
        }
    }
    return -1;                               //循环结束,没找到。
}

扩展

  上面要求的是没有重复元素,现在稍微扩展一下,可以有重复的元素,其它的要求不变。

思路:大致思路和原来相同,只不过相等的情况单独处理。找到的元素位置,并不一定是第一次出现的位置。

  • arr[L]<arr[m];左边有序
  • arr[L]>arr[m];右边有序
  • arr[L]=arr[m];相等,特殊处理,++L(L=m+1也可以)。

和arr[R]比较也可以。

 

int BSearch(int *arr, int len, int X){
    int L = 0, R = len - 1;
    int m;
    while (L <= R){                         //循环条件
        m = (L + R) / 2;
        if (arr[m] == X)                    //找到了,终止
            return m;
        if (arr[m] < arr[L]){               //右侧有序
            if (arr[m] < X && arr[R] >= X){
                L = m + 1;
            }
            else
                R = m - 1;
        }
        else if (arr[m] > arr[L]){          //左侧有序
            if (arr[m] > X && arr[L] <= X){
                R = m - 1;
            }
            else
                L = m + 1;
        }
        else                                //相等情况
            L = m + 1;
    }
    return -1;                              //循环结束,没找到。
}

 

2015-10-14 15:32:56

 

posted @ 2015-10-13 21:33  一只背影  阅读(5965)  评论(3编辑  收藏  举报