如何在O(log(N))时间内找到排序数组中在一定范围内的整数数?

时间:2013-03-08 10:52:21

标签: java arrays search binary-search

我有一个排序的整数数组:

{1,2,4,4,5,8,12,15,15,23,54}

我想知道该数组中有多少数字落在一个范围之间,比如说4到15之间。

{4,4,5,6,12,15,15}

因此,数组中有7个项目在该范围内。

我需要在O(log(N))时间执行此操作,我认为我可以使用二进制搜索,但由于重复,因此无法找到下限和上限。

如何在O(log(N))时间内完成?

我想过从前面循环,然后从最后循环,但这可能达到O(N)

4 个答案:

答案 0 :(得分:2)

可以通过范围二进制搜索在 O(logN)时间内完成下限和上限。下限和上限的范围二进制搜索是不同。这里不同意味着他们有不同的停止标准和返回步骤。

  1. 对于下限(左范围),您可以调用以下函数来获取值大于或等于它的有序数组中的索引,否则为-1。

    int binarySearchForLeftRange(int a[], int length, int left_range)
    {
        if (a[length-1] < left_range)
            return -1;
    
        int low = 0;
        int high = length-1;
    
        while (low<=high)
        {
            int mid = low+((high-low)/2);
    
            if(a[mid] >= left_range)
                high = mid-1;
            else //if(a[mid]<i)
                low = mid+1;
        }
    
        return high+1;
    }
    
  2. 对于上限(右侧范围),您可以调用以下函数来获取值小于或等于它的有序数组中的索引,否则为-1。

    int binarySearchForRightRange(int a[], int length, int right_range)
    {
        if (a[0] > right_range)
            return -1;
    
        int low = 0;
        int high = length-1;
    
        while (low<=high)
        {
            int mid = low+((high-low)/2);
    
            if(a[mid] > right_range)
                high = mid-1;
            else //if(a[mid]<i)
                low = mid+1;
        }
    
        return low-1;
    }
    
  3. 最后,如果您想获得此范围内的元素数量,可以根据上述两个函数的返回值轻松实现。

    int index_left = binarySearchForLeftRange(a, length, left_range);
    int index_right = binarySearchForRightRange(a, length, right_range);
    
    if (index_left==-1 || index_right==-1 || index_left>index_right)
        count = 0;
    else
        count = index_right-index_left+1;
    

  4. 测试 :(带有重复项)

        int a[] = {1,2,4,4,5,8,12,15,15,23,54};
        int length = sizeof(arr)/sizeof(arr[0]);
    
        int left_range = 4;
        int right_range = 15;
        int index_left = binarySearchForLeftRange(a, length, left_range); // will be 2
        int index_right = binarySearchForRightRange(a, length, right_range); // will be 8
    
        int count; // will be 7
        if (index_left==-1 || index_right==-1 || index_left>index_right)
            count = 0;
        else
            count = index_right-index_left+1;
    

    编辑:当然,您可以通过传递一个额外的标志来将前两个函数合并为一个,以指示它是下限或上限,但如果不是则会更清楚。你的选择!

答案 1 :(得分:0)

在二进制搜索中,当您找到所需的号码或号码不在列表中时,您将停止递归过程。
在这里,您必须修改二进制搜索算法。从较低范围开始,例如 a ,继续重复,直到找到小于 a 的数字。在这样做的同时保持两个指数,如。如果您要比较的数字小于 a ,请更新低,否则更新为高。现在您拥有较低的索引,现在递归地应用此过程以查找大于此 a 的数字。该指数将给出起始指数 现在,对于上限范围进行免费赠送,您将获得结束指数 答案是ending index - starting index + 1

imin = 0, imax = A.size()-1
low = 0, high = A.size()-1
while(imax >= imin)
{
   imid = mid(imin,imax)
   if(key < A[imid])
   {
       imax = imid -1
       high = imid
   }
   else if(key > A[imid])
   {
       imin = imid + 1
       low = imid
   }
   else 
   {
       high = imid
       break;
   }
 }

现在,一旦它从循环中检出imin > imax,如果是,那么较低范围索引将是imax。否则,使用相同的密钥再次使用imin = lowimax = high重复搜索,直到达到条件imin > imax。对上限范围重复相同的操作 时间复杂度介于O(log(n))O(n)

之间

答案 2 :(得分:0)

您需要修改二进制搜索,该搜索具有参数,无论是查找元素的第一个还是最后一个 你必须自己编写修改过的binsearch。

答案 3 :(得分:0)

我没有解释我已经在java中给出了代码,如果你想要你可以改进它。

 public class Test {

public static int binSearch(int array[], int key, int left, int right,boolean lb)
{
int mid = left + (right-left)/2;
if (key < array[mid])
    return binSearch(array, key, left, mid-1,lb);
else if (key > array[mid])
    return binSearch(array, key, mid+1, right,lb);
else if (key == array[mid]){
    if(!lb){
    if(key==array[mid+1]){
        int ctr=mid+1;
        while(key==array[++ctr]);
        return ctr--;
      }
    else
        return mid;
    }
    else{
    if(key==array[mid-1]){
        int ctr=mid-1;
        while(key==array[--ctr]);
        return ctr++;
    }
    else
        return mid;
   }

}
return -0; // Not Found

}

public static void main(String[] args) {
int a[]={1,2,4,4,5,8,12,15,15,23,54};
int start=binSearch(a, 4, 0, a.length,true);
int end=binSearch(a, 15, 0, a.length,false);
System.out.println(end-start+1);// number are include
}

}