Check if a number exists in a given set of ranges

99封情书 提交于 2019-12-10 10:37:13

问题


Suppose we have a set of N ranges, (A1, B1) (A2, B2) (A3, B3) ... (An, Bn), where Ai denotes the starting point and Bi denotes the ending point of a range. (Ai, Bi are positive integers)

How do we check using Binary Search if the given integer, say X, exists in at least one of the N ranges?

My approach:

  1. Sort the ranges by x-coordinate first and then by y-coordinate.

  2. Find the smallest x-coordinate greater or equal to X.

  3. Check if that range is satisfied.

  4. If yes, we have a solution.

Now, if that range doesnt contain X, what should be my next step?

Or, should the solution be entirely different?


回答1:


What I got from your problem description is that you have pairs like (a1,b1) , (a2,b2). Where ax is start of range and bx is end. Now you are given a number n and you want to search if that number is in any of ranges.
First sort then merge the overlapping ranges and then apply binary search:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
    vector < pair <int , int> > b;
    b.push_back(make_pair(5,10));
    b.push_back(make_pair(75,100));
    b.push_back(make_pair(33,67));
    b.push_back(make_pair(9,21));
    b.push_back(make_pair(28,67));
    int m = b.size();
    sort(b.begin(), b.end());
    int j = 0;
    for (int i = 1; i < m; i++) {
        if (b[i].first <= b[j].second) {
            if (b[i].second > b[j].second) {
                b[j].second = b[i].second;
            }
        } 
        else {
            j++;
            b[j] = b[i];
        }
    }
    m = j + 1;
    for(int i = 0; i< m;i ++) {
        cout << b[i].first << " " << b[i].second << endl;
    }
    // Apply binary search now
    return 0;
}

I hope this will solve your problem. I have left the binary search part for you as exercise.




回答2:


First of all, if the ranges aren't sorted, you're better off checking one by one instead of doing any fancy binary search, because checking each range will be at most O(n), whereas sorting and then binary searching will be at least O(n log n).

Anyway, in this case I'd consider all the ranges with the same x-coordinate to be a single node, so when you're binary-searching, the middle node you get will actually be the group of ranges that have the same x-coordinate. You'd then check the y-coordinate of the last range in that node. If the number is not between those two, then the number is not contained in any of the ranges of that node, so you should either go left or right depending on whether the number is higher or lower than the x or y-coordinates.

Here's a full working example in Python:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import random
import itertools

MAX = 50
NUM_RANGES = 30

THE_NUMBER = random.randint(0, MAX)

ranges = []
# Generate random ranges
for e in range(NUM_RANGES):
    x = random.randint(0, MAX - 1)
    y = random.randint(x + 1, MAX)

    ranges.append((x,y))

# Group the ranges by starting coordinate
grouped_ranges = {x: [e for e in ranges if e[0] == x] for x in (e[0] for e in ranges)}

## Binary search
gkeys = grouped_ranges.keys()
gkeys_range = [0, len(gkeys)]

get_mid_key = lambda: (gkeys_range[1] + gkeys_range[0])/2
get_mid = lambda: grouped_ranges[gkeys[get_mid_key()]]

print "THE NUMBER:", THE_NUMBER
print "THE RANGES:", grouped_ranges

while 1:
    # Get middle element
    mid = get_mid()

    print gkeys_range

    old_range = gkeys_range[:]

    if THE_NUMBER < mid[0][0]:
        gkeys_range[1] = get_mid_key()
    elif THE_NUMBER > mid[-1][1]:
        gkeys_range[0] = get_mid_key()
    else:
        print "In this range:", mid
        break

    if gkeys_range == old_range:
        print "Not in any range"
        break


来源:https://stackoverflow.com/questions/26296761/check-if-a-number-exists-in-a-given-set-of-ranges

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!