我有一个排序的整数数组:
{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)
答案 0 :(得分:2)
可以通过范围二进制搜索在 O(logN)时间内完成下限和上限。下限和上限的范围二进制搜索是不同。这里不同意味着他们有不同的停止标准和返回步骤。
对于下限(左范围),您可以调用以下函数来获取值大于或等于它的有序数组中的索引,否则为-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;
}
对于上限(右侧范围),您可以调用以下函数来获取值小于或等于它的有序数组中的索引,否则为-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;
}
最后,如果您想获得此范围内的元素数量,可以根据上述两个函数的返回值轻松实现。
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;
测试 :(带有重复项)
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 = low
和imax = 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
}
}