0

I have std::set<std::pair<int, int>> intervals which it's values are some intervals, it is somthing similar to this:

{ 0, 5 },
{ 5, 8 },
{ 8, 10 }

and I have a number x can I find in which interval it is using lower_bound or upper_bound?

I need a solution with O(log(N)) complexity.

Because I remember that I saw someone doing it someway like this:

int x;
std::set<std::pair<int, int>> intervals;
cin >> x;
auto ans = intervals.upper_bound({ x, INF })

and I don't remember what was the value of INF

Note: the intervals aren't intersecting.

Muaath
  • 579
  • 3
  • 19
  • Do you remember what [`INF`](https://en.wikipedia.org/wiki/Infinity) is short for? (Don't you wish people did not abbreviate names?) – JaMiT Jul 20 '22 at 01:55
  • I’d use a vector or an array, holding the boundary values 0, 5, 8, and 10. `std::lower_bound` will have logarithmic time complexity. – Pete Becker Jul 20 '22 at 02:23
  • 2
    use {x, INT_MAX} and upper_bound will find the next interval, then just back to x's interval. some code not elegant, https://godbolt.org/z/h97P5jMEh – che.wang Jul 20 '22 at 02:51
  • @JaMit I remember INF was something either INT_MAX or INT_MIN, anyway, thanks to everybody – Muaath Jul 20 '22 at 15:45
  • Thanks @che.wang !! If your comment was an answer, I'm gonna accept it!! – Muaath Jul 20 '22 at 15:57
  • @Muaath *"I remember INF was something either INT_MAX or INT_MIN"* -- I'm pretty sure that "INF" is not an abbreviation for either of those. The correct answer is that "INF" is short for "infinity". Once you know that, choosing between the biggest representable integer and, well, any other integer value should be a piece of cake. ;) – JaMiT Jul 21 '22 at 02:29

1 Answers1

1

First of all, if you want to have a set of continuous ranges, you should simply represent them as a set that keeps only the beginning of each range.

set<int> boundaries { 0, 5, 8, 10 };

If you really want to use a structure that keeps both ends of a range, the following will allow you to search in O(log(N)). In the case of keeping both ends, it is possible to express other than continuous ranges set, so this example intentionally omits [6, 8). If the structure keeps both ends, it is also possible to express overlapping ranges set. In that case, we would have to search for more than one range. I left that example out.

#include <algorithm>
#include <limits>
#include <numeric>
#include <set>

using namespace std;
int main()
{
    set<pair<int, int>> intervals{ { 0, 5 },
                                   { 5, 6 },
                                   { 8, 10 } }; // drop {6, 8} version.
    {
        constexpr auto INF = numeric_limits<int>::max();
        auto find = [&](const int x) {
            auto next = intervals.upper_bound({ x, INF });
            if (next != intervals.begin()) {
                if (auto ans = prev(next); x < ans->second)
                    return ans;
            }
            return intervals.end();
        };
        for (int x = -1; x <= 11; ++x) {
            if (auto ans = find(x); ans != intervals.end()) {
                printf("%d is in [%d, %d)\n", x, ans->first, ans->second);
            } else {
                printf("%d is not in any range\n", x);
            }
        }
    }

    set<int> boundaries{ 0, 5, 8, 10 };
    {
        auto find = [&](const int x) {
            auto next = boundaries.upper_bound(x);
            if (next != boundaries.begin()) {
                return prev(next);
            }
            return boundaries.end();
        };

        for (int x = -1; x <= 11; ++x) {
            if (auto ans = find(x); ans != boundaries.end()) {
                if (auto nx = next(ans); nx != boundaries.end()) {
                    printf("%d is in [%d, %d)\n", x, *ans, *nx);
                } else {
                    printf("%d is in [%d, inf)\n", x, *ans);
                }
            } else {
                printf("%d is in [-inf, %d)\n", x, *boundaries.begin());
            }
        }
    }
}

stdout is here.

// == set<pair<int, int>>
-1 is not in any range
0 is in [0, 5)
1 is in [0, 5)
2 is in [0, 5)
3 is in [0, 5)
4 is in [0, 5)
5 is in [5, 6)
6 is not in any range
7 is not in any range
8 is in [8, 10)
9 is in [8, 10)
10 is not in any range
11 is not in any range

// == set<int>
-1 is in [-inf, 0)
0 is in [0, 5)
1 is in [0, 5)
2 is in [0, 5)
3 is in [0, 5)
4 is in [0, 5)
5 is in [5, 8)
6 is in [5, 8)
7 is in [5, 8)
8 is in [8, 10)
9 is in [8, 10)
10 is in [10, inf)
11 is in [10, inf)