8
\$\begingroup\$

Given a set of intervals \$\mathcal{I} = \{I_1, \ldots, I_m\}\$, where each interval \$I_j\$ is represented by its bounds \$(a_j, b_j)\$, find a partition \$\mathcal{T}\$ of \$\mathcal{I}\$ of minimal cardinality such that for each set \$T_i \in \mathcal{T}\$ it holds \$\bigcap T_i \ne \emptyset\$. In other words, find a partition of minimal cardinality where all the intervals inserted in the same set have a common element.

Elements \$\{a_j, b_j\}\$ can be integers, floats, chars, strings, or any other data type that has a total order and at least \$16\$ elements * (boolean is not admissible). Your solution must support at least one such data type of your choice.

*: why \$16\$ and not any other number? It's an arbitrary limit, I want to give freedom to use any strange data type, but I do not want loopholish solutions.

You can either output:

  1. partition \$\mathcal{T} = \{T_1, \ldots, T_k\}\$, or alternatively
  2. a set of numbers \$S = \{s_1, \ldots, s_k \}\$ such that \$s_i \in \bigcap T_i\$ for each \$i\$.

Testcases

input                        output (format 1)                  output (format 2)
{}:                          [],                                [],
{(0, 1)}:                    [{(0, 1)}],                        [0],
{(0, 1), (2, 3)}:            [{(0, 1)}, {(2, 3)}],              [0, 2],
{(1, 2), (0, 3)}:            [{(1, 2), (0, 3)}],                [1],
{(0, 2), (1, 3)}:            [{(0, 2), (1, 3)}],                [1],
{(1, 2), (3, 4), (0, 5)}:    [{(1, 2), (0, 5)}, {(3, 4)}],      [1, 3],
{(0, 1), (4, 5), (2, 3)}:    [{(0, 1)}, {(2, 3)}, {(4, 5)}],    [0, 2, 4],
{(4, 5), (1, 2), (0, 3)}:    [{(1, 2), (0, 3)}, {(4, 5)}],      [1, 4],
{(0, 1), (2, 5), (3, 4)}:    [{(0, 1)}, {(2, 5), (3, 4)}],      [0, 3],
{(0, 2), (3, 5), (1, 4)}:    [{(0, 2), (1, 4)}, {(3, 5)}],      [1, 3],

Rules

  • you can use any reasonable I/O format, for example:
    • the input can be a list/set of tuples, or two lists;
    • in case 1., the output can be a list/set of lists/sets of intervals; each interval can be represented as a tuple, or the index of its position in the input;
    • in case 2., the output can be a list/set of numbers;
  • you can take the cardinality \$m\$ of the input set as an additional input;
  • the input set \$\mathcal{I}\$ may be empty (in this case you have to output an empty list/set);
  • you can assume each interval is not empty nor degenerate, i.e. \$a_j < b_j\$;
  • you can assume intervals are left-closed or left-open, and if they are right-closed or right-open, as long as it's consistent for all intervals;
  • you cannot assume the intervals in the input are sorted according to any particular criteria.

This is codegolf, so the shortest code wins. Bonus \$-i\$ bytes if your solution works in less than exponential time.


Tips

  • I think using closed intervals is the easiest way. I would have put it as a rule, but I prefer to leave freedom.
  • by lexicographically sorting the intervals, a minimal solution can be computed using a greedy algorithm.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ A worked example or some test cases would be helpful \$\endgroup\$ Commented Jun 24, 2023 at 19:34
  • \$\begingroup\$ Does "Elements {aj,bj} can be integers, floats, chars, strings, or any other data type with a total order." mean we can choose which of these they are, or that we have to support all of these? \$\endgroup\$ Commented Jun 26, 2023 at 2:54
  • \$\begingroup\$ you can chose which type they are \$\endgroup\$ Commented Jun 26, 2023 at 10:02

6 Answers 6

5
\$\begingroup\$

05AB1E, 11 bytes

˜æ.ΔI€Ÿ¢€àP

Try it online! or try all test cases.

Finds the smallest subset of the ranges' bounds such that each of the ranges contains one of the values in set.

Explanation

˜      flatten the input ranges, to get a list of all bounds
æ      push all subsets, sorted by size
.Δ     find the first (and smallest) one such that:
 I      push the input again
 €      map each interval in the input
  Ÿ      to the list of integers it contains
 ¢      count how many times each of these values appear in the subset. Because the minimum subset doesn't contain duplicates, each of these is 0 or 1.
 ۈ     for each of the intervals, find the maximum
 P      and take the product, check if all of them are 1
\$\endgroup\$
4
\$\begingroup\$

Python 3.8 (pre-release), 59 bytes

f=lambda a:a and(z:=max(a)[0],*f([p for p in a if p[1]<z]))

Try it online!

Takes a sequence of pairs representing left-closed, right-open intervals and returns a tuple of points.

Same algorithm as earlier but upside down.

Retired Python, 62 bytes (-4 thanks @Jonathan Allan)

f=lambda*a:a and(z:=min(map(max,a)),*f(*filter([z].__le__,a)))

Attempt This Online!

Retired Python, 66 bytes

f=lambda*a:a and(z:=min(y for x,y in a),*f(*filter([z].__le__,a)))

Attempt This Online!

Takes a splatted sequence of lists representing left-open, right-closed intervals and returns a tuple of points.

Time-complexity is quadratic I believe.

How?

At each iteration finds the smallest right boundary. This point is used to define the next cluster. All intervals with smaller left boundary contain the point and are filtered out before the next iteration.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Clever, @JonathanAllan! \$\endgroup\$ Commented Jun 25, 2023 at 12:41
2
\$\begingroup\$

Jelly, 12 bytes (\$-i\$)

>Ạ¥ƇṀ€Ṃ$$ƬḟƝ

A monadic Link that accepts the intervals as a list of pairs and yields a minimal cardinality partition with self-intersecting parts as a list of lists of pairs.

Try it online! Or see the test-suite.

How?

>Ạ¥ƇṀ€Ṃ$$ƬḟƝ - Link: Intervals
         Ƭ   - collect up while distinct, applying:
        $    -   last two links as a monad - f(CurrentIntervals):
       $     -     last two links as a monad - f(CurrentIntervals):
    Ṁ€       -       maximum of each
      Ṃ      -       minimum -> "M"
   Ƈ         -     keep those (I in CurrentIntervals) for which:
  ¥          -       last two links as a dyad - f(I, M):
>            -         {I} greater than {M}? (vectorises)
 Ạ           -         all?
           Ɲ - for neighbouring pairs - f(L, R):
          ḟ  -   {L} filter discard {R}
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 16 bytes

W⌊⌈θ«≔Φθ‹⌈κιθ⟦Iι

Try it online! Link is to verbose version of code. Explanation: Port of @Albert.Lang's upside-down answer.

W⌊⌈θ«

While intervals remain, find the beginning of the rightmost interval. (This depends on underhanded behaviour of the version of Charcoal on TIO which returns None if it can't work out whether is supposed to be Minimum or Floor.)

≔Φθ‹⌈κιθ

Remove the intervals that contain that point.

⟦Iι

Output the point.

\$\endgroup\$
2
\$\begingroup\$

Nekomata, 11 bytes

Oᵖᵐ{Ťđṁ<}aş

Attempt This Online!

Oᵖᵐ{Ťđṁ<}aş
O               Find a set partition of the input
 ᵖ              such that
  ᵐ{    }       for each subset in the partition
    Ťđ          transpose to get a list of heads and a list of tails
      ṁ<        check that all heads are less than the smallest tail
         aş     Find the shortest such partition

By default, Nekomata outputs all possible solutions. If you want only one solution, you can add the -1 flag.

\$\endgroup\$
0
\$\begingroup\$

Pyth, 12 bytes

hlDm{.nd*FrM

Try it online!

Uses half inclusive range. Looks at all lists where one element is from each range, deduplicates this and then finds the shortest.

Explanation

hlDm{.nd*FrMQ    # implicitly add Q
                 # implicitly assign Q = eval(input())
          rMQ    # map elements of Q to their ranges
        *F       # fold over cartesian product
   m             # map over lambda d
     .nd         #   flatten d to an unnested list
    {            #   deduplicate
 lD              # sort by length
h                # take the first element
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.