一尘不染

在圆形排序数组中搜索元素

algorithm

我们要在圆形排序数组中搜索给定元素,其复杂度不大于O(log n)
示例:搜索13{5,9,13,1,3}

我的想法是将圆形数组转换为常规排序的数组,然后对结果数组进行二进制搜索,但是我的问题是我提出的算法很愚蠢,它O(n)在最坏的情况下会采用:

for(i = 1; i < a.length; i++){
    if (a[i] < a[i-1]){
        minIndex = i; break;
    }
}

然后根据以下关系确定第ith个元素的相应索引:

(i + minInex - 1) % a.length

很明显,我的算法(从循环到常规)的转换可能需要O(n),因此我们需要一个更好的算法。

根据ire_and_curses的想法,这是Java中的解决方案:

public int circularArraySearch(int[] a, int low, int high, int x){
    //instead of using the division op. (which surprisingly fails on big numbers)
    //we will use the unsigned right shift to get the average
    int mid = (low + high) >>> 1;
    if(a[mid] == x){
        return mid;
    }
    //a variable to indicate which half is sorted
    //1 for left, 2 for right
    int sortedHalf = 0;
    if(a[low] <= a[mid]){
        //the left half is sorted
        sortedHalf = 1;
        if(x <= a[mid] && x >= a[low]){
            //the element is in this half
            return binarySearch(a, low, mid, x);
        }
    }
    if(a[mid] <= a[high]){
        //the right half is sorted
        sortedHalf = 2;
        if(x >= a[mid] && x<= a[high] ){
            return binarySearch(a, mid, high, x);
        }
    }
    // repeat the process on the unsorted half
    if(sortedHalf == 1){
        //left is sorted, repeat the process on the right one
        return circularArraySearch(a, mid, high, x);
    }else{
        //right is sorted, repeat the process on the left
        return circularArraySearch(a, low, mid, x);
    }
}

希望这会起作用。


阅读 203

收藏
2020-07-28

共1个答案

一尘不染

您可以利用对数组进行排序的事实来做到这一点,但支点值及其邻居之一的特殊情况除外。

  • 找到数组的中间值a。
  • 如果为a[0] < a[mid],则对数组前半部分中的所有值进行排序。
  • 如果为a[mid] < a[last],则对数组后半部分中的所有值进行排序。
  • 取排序后的一半,并检查您的值是否在其中(与那一半的最大idx比较)。
  • 如果是这样,只需二进制搜索那一半。
  • 如果不是,则必须在未排序的一半内。拿一半再重复这个过程,确定那一半中的哪一半被排序,依此类推。
2020-07-28