[英]Binary search to find the range in which the number lies
我有一個數組
Values array: 12 20 32 40 52
^ ^ ^ ^ ^
0 1 2 3 4
我必須在其上執行二進制搜索才能找到數字所在范圍的索引。 例如:
我以下列方式實現了二分搜索,這對於案例 1 和 3 是正確的,但如果我們搜索案例 2 或 52、55 32 等,則不正確。
#include <iostream>
using namespace std;
int findIndex(int values[], int number, unsigned first, unsigned last)
{
unsigned midPoint;
while(first<last)
{
unsigned midPoint = (first+last)/2;
if (number <= values[midPoint])
last = midPoint -1;
else if (number > values[midPoint])
first = midPoint + 1;
}
return midPoint;
}
int main()
{
int a[] = {12, 20, 32, 40, 52};
unsigned i = findIndex(a, 55, 0, 4);
cout << i;
}
不允許使用其他變量,例如bool found
。
C 或 C++ 中的范圍通常以直接指向下限的形式給出,但超過上限。 除非您感到極度自虐,否則您可能也希望在搜索中堅持該慣例。
假設你要遵循那個,你的last = midpoint-1;
是不正確的。 相反,你想最后設定為一個過去你要真正使用范圍的結束,所以它應該是last = midpoint;
你也只需要一個比較,而不是兩個。 在二分查找中,只要兩個邊界不相等,您將把下限或上限設置為中心點,因此您只需要進行一次比較就可以決定哪個。
至少按照慣例,在 C++ 中,您使用<
而不是<=
、 >
等進行所有比較。上述任何一種都可以工作,但遵循僅使用<
的約定可避免對包含的類型強加額外的(不必要的)要求.
雖然大多數面試官可能並不關心,但當你做midpoint = (left + right)/2;
時也有潛在的溢出midpoint = (left + right)/2;
. 我通常更喜歡midpoint = left + (right - left)/2;
考慮到這些,代碼可能如下所示:
template <class T>
T *lower_bound(T *left, T *right, T val) {
while (left < right) {
T *middle = left + (right - left) / 2;
if (*middle < val)
left = middle + 1;
else
right = middle;
}
return left;
}
template <class T>
T *upper_bound(T *left, T *right, T val) {
while (left < right) {
T *middle = left + (right - left) / 2;
if (val < *middle)
right = middle;
else
left = middle + 1;
}
return left;
}
為什么不使用標准庫函數?
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main() {
for (int input = 10; input < 55; input++) {
cout << input << ": ";
// Your desire:
vector<int> v = { 12, 20, 32, 40, 52 };
if (input < v.front() || input > v.back()) {
cout << "Not found" << endl;
} else {
auto it = upper_bound(v.begin(), v.end(), input);
cout << it - v.begin() - 1 << endl;
}
}
}
注意:一個非常酷的網站 - http://en.cppreference.com/w/cpp/algorithm
這將在min(A[i]) <= key <=max(A[i])
int binary_search(int A[],int key,int left, int right)
{
while (left <= right) {
int middle = left + (right - left) / 2;
if (A[middle] < key)
left = middle+1;
else if(A[middle] > key)
right = middle-1;
else
return middle;
}
return (left - 1);
}
對於輸入
4
1 3 8 10
4
輸出
3(3 和 8 中的最小值)
#include <stdio.h>
int main()
{
int c, first, last, middle, n, search, array[100];
scanf("%d",&n);
for (c = 0; c < n; c++)
scanf("%d",&array[c]);
scanf("%d", &search);
first = 0;
last = n - 1;
middle = (first+last)/2;
while (first <= last) {
if (array[middle] < search)
{
first = middle + 1; }
else if (array[middle] == search) {
break;
}
else
{
last = middle - 1;
}
middle = (first + last)/2;
}
printf("%d\n",array[middle]);
return 0;
}
對成功的常規二分搜索返回鍵的索引。 如果找不到鍵,它總是停在比我們正在搜索的鍵大的最低鍵的索引處。 我想以下修改后的二進制搜索算法會起作用。
Given sorted array A
Find a key using binary search and get an index.
If A[index] == key
return index;
else
while(index > 1 && A[index] == A[index -1]) index = index -1;
return index;
binsrch(array, num, low, high) {
if (num > array[high])
return high;
while(1) {
if (low == high-1)
return low;
if(low >= high)
return low-1;
mid = (low+high)/2
if (num < arr[mid])
high = mid;
else
low = mid+1;
}
}
這是一個更具體的答案
int findIndex(int values[],int key,int first, int last)
{
if(values[first]<=key && values[first+1]>=key)// stopping condition
{
return first;
}
int imid=first+(last-first)/2;
if(first==last || imid==first)
{
return -1;
}
if(values[imid]>key)
{
return findIndex(values,key,first,imid);
}
else if(values[imid]<=key)
{
return findIndex(values,key,imid,last);
}
}
我覺得這更符合你正在尋找的東西......我們不會在這件事的最后一個價值上胡說八道
/* binary_range.c (c) 2016 adolfo@di-mare.com */
/* http://stackoverflow.com/questions/10935635 */
/* This code is written to be easily translated to Fortran */
#include <stdio.h> /* printf() */
#include <assert.h> /* assert() */
/** Find the biggest index 'i' such that '*nSEED <= nVEC[i]'.
- nVEC[0..N-1] is an strict ascending order array.
- Returns and index in [0..N].
- Returns 'N' when '*nSEED>nVEC[N-1]'.
- Uses binary search to find the range for '*nSEED'.
*/
int binary_range( int *nSEED, int nVEC[] , int N ) {
int lo,hi, mid,plus;
if ( *nSEED > nVEC[N-1] ) {
return N;
}
for (;;) { /* lo = binary_range_search() */
lo = 0;
hi = N-1;
for (;;) {
plus = (hi-lo)>>1; /* mid = (hi+lo)/2; */
if ( plus == 0 ) { assert( hi-lo==1 );
if (*nSEED <= nVEC[lo]) {
hi = lo;
}
else {
lo = hi;
}
}
mid = lo + plus; /* mid = lo + (hi-lo)/2; */
if (*nSEED <= nVEC[mid]) {
hi = mid;
}
else {
lo = mid;
}
if (lo>=hi) { break; }
}
break;
} /* 'lo' is the index */
/* This implementation does not use division. */
/* ========================================= */
assert( *nSEED <= nVEC[lo] );
return lo;
}
/** Find the biggest index 'i' such that '*nSEED <= nVEC[i]'.
- nVEC[0..N-1] is an strict ascending order array.
- Returns and index in [0..N].
- Returns 'N' when '*nSEED>nVEC[N-1]'.
- Uses sequential search to find the range for '*nSEED'.
*/
int sequential_range( int* nSEED, int nVEC[] , int N ) {
int i;
if ( *nSEED > nVEC[N-1] ) {
return N;
}
i=0;
while ( i<N ) {
if ( *nSEED <= nVEC[i] ) { break; }
++i;
}
return i;
}
/** test->stackoverflow.10935635(). */
void test_10935635() {
{{ /* test.stackoverflow.10935635() */
/* http://stackoverflow.com/questions/10935635 */
/* binary_range search to find the range in which the number lies */
/* 0 1 2 3 4 */
int nVEC[] = { 12,20,32,40,52 }; int val;
int N = sizeof(nVEC)/sizeof(nVEC[0]); /* N = DIM(nVEC[]) */
val=19; val = binary_range( &val,nVEC,N );
/* 19 -> [12 < (19) <= 20] -> return 1 */
val=19; assert( binary_range( &val,nVEC,N ) == 1 );
/* 22 -> [20 < (22) <= 32] -> return 2 */
val=22; assert( binary_range( &val,nVEC,N ) == 2 );
/* 40 -> [32 < (40) <= 40] -> return 3 */
val=40; assert( binary_range( &val,nVEC,N ) == 3 );
/* Everything over 52 returns N */
val=53; assert( binary_range( &val,nVEC,N ) == N );
}}
}
/** Test program. */
int main() {
if (1) {
printf( "\ntest_10935635()" );
test_10935635();
}
printf( "\nEND" );
return 0;
}
/* Compiler: gcc.exe (tdm-1) 4.9.2 */
/* IDE: Code::Blocks 16.01 */
/* Language: C && C++ */
/* EOF: binary_range.c */
我知道這是一個舊線程,但由於我必須解決類似的問題,所以我想我會分享它。 給定一組不重疊的整數范圍,我需要測試給定的值是否位於這些范圍中的任何一個。 以下(在 Java 中)使用修改后的二分搜索來測試值是否位於已排序(從最低到最高)的整數范圍集合內。
/**
* Very basic Range representation for long values
*
*/
public class Range {
private long low;
private long high;
public Range(long low, long high) {
this.low = low;
this.high = high;
}
public boolean isInRange(long val) {
return val >= low && val <= high;
}
public long getLow() {
return low;
}
public void setLow(long low) {
this.low = low;
}
public long getHigh() {
return high;
}
public void setHigh(long high) {
this.high = high;
}
@Override
public String toString() {
return "Range [low=" + low + ", high=" + high + "]";
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//Java implementation of iterative Binary Search over Ranges
class BinaryRangeSearch {
// Returns index of x if it is present in the list of Range,
// else return -1
int binarySearch(List<Range> ranges, int x)
{
Range[] arr = new Range[ranges.size()];
arr = ranges.toArray(arr);
int low = 0, high = arr.length - 1;
int iters = 0;
while (low <= high) {
int mid = low + (high - low) / 2; // find mid point
// Check if x is present a
if (arr[mid].getLow() == x) {
System.out.println(iters + " iterations");
return mid;
}
// If x greater, ignore left half
if (x > arr[mid].getHigh()) {
low = mid + 1;
}
else if (x >= arr[mid].getLow()) {
System.out.println(iters + " iterations");
return mid;
}
// If x is smaller, ignore right half of remaining Ranges
else
high = mid - 1;
iters++;
}
return -1; // not in any of the given Ranges
}
// Driver method to test above
public static void main(String args[])
{
BinaryRangeSearch ob = new BinaryRangeSearch();
// make a test list of long Range
int multiplier = 1;
List<Range> ranges = new ArrayList<>();
int high = 0;
for(int i = 0; i <7; i++) {
int low = i + high;
high = (i+10) * multiplier;
Range r = new Range(low, high);
multiplier *= 10;
ranges.add(r);
}
System.out.println(Arrays.toString(ranges.toArray()));
int result = ob.binarySearch(ranges, 11);
if (result == -1)
System.out.println("Element not present");
else
System.out.println("Element found at "
+ "index " + result);
}
}
我的python實現:
時間復雜度:O(log(n)) 空間復雜度:O(log(n))
def searchForRange(array, target):
range = [-1, -1]
alteredBinarySerach(array, target, 0, len(array) -1, range, True)
alteredBinarySerach(array, target, 0, len(array) -1, range, False)
return range
def alteredBinarySerach(array, target, left, right, range, goLeft):
if left > right:
return
middle = (left+ right)//2
if array[middle] > target:
alteredBinarySerach(array, target, left, middle -1, range, goLeft)
elif array[middle] < target:
alteredBinarySerach(array, target, middle +1, right, range, goLeft)
else:
if goLeft:
if middle == 0 or array[middle -1] != target:
range[0] = middle
else:
alteredBinarySerach(array, target, left, middle -1 , range, goLeft)
else:
if middle == len(array) -1 or array[middle+1] != target:
range[1] = middle
else:
alteredBinarySerach(array, target, middle +1, right , range, goLeft)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.