Binary search to find the range in which the number lies

后端 未结 10 729
悲哀的现实
悲哀的现实 2020-12-16 18:31

I have an array

Values array: 12 20 32 40 52
              ^  ^  ^  ^  ^
              0  1  2  3  4

on which I have to perform binary sear

相关标签:
10条回答
  • 2020-12-16 18:48

    I know this is an old thread, but since I had to solve a similar problem I thought I would share it. Given a set of non-overlapping ranges of integers, I need to test if a given value lies in any of those ranges. The following (in Java), uses a modified binary search to test if a value lies within the sorted (lowest to highest) set of integer ranges.

    /**
     * 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); 
    } 
    } 
    
    0 讨论(0)
  • 2020-12-16 18:55

    For INPUT

    4

    1 3 8 10

    4

    OUTPUT

    3 (the minimum of the 3 and 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;   
     }
    
    0 讨论(0)
  • 2020-12-16 18:56

    A range in C or C++ is normally given as the pointing directly to the lower bound, but one past the upper bound. Unless you're feeling extremely masochistic, you probably want to stick to that convention in your search as well.

    Assuming you're going to follow that, your last = midpoint-1; is incorrect. Rather, you want to set last to one past the end of the range you're going to actually use, so it should be last = midpoint;

    You also only really need one comparison, not two. In a binary search as long as the two bounds aren't equal, you're going to set either the lower or the upper bound to the center point, so you only need to do one comparison to decide which.

    At least by convention, in C++, you do all your comparisons using < instead of <=, >, etc. Any of the above can work, but following the convention of using only < keeps from imposing extra (unnecessary) requirements on contained types.

    Though most interviewers probably don't care, there's also a potential overflow when you do midpoint = (left + right)/2;. I'd generally prefer midpoint = left + (right - left)/2;

    Taking those into account, code might look something like this:

    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;
    }
    
    0 讨论(0)
  • 2020-12-16 18:56

    here is a more specific answer

    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);
        }
    
    }
    

    I feel this is more inline to what you were looking for...and we won't crap out on the last value in this thing

    0 讨论(0)
  • 2020-12-16 18:56

    My python implementation:

    Time complexity: O(log(n)) Space complexity: 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)
    
    0 讨论(0)
  • 2020-12-16 18:59

    Why not to use standard library functions?

    #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;
            }
        }
    }
    

    Note: a pretty-cool site - http://en.cppreference.com/w/cpp/algorithm

    0 讨论(0)
提交回复
热议问题