0

Let's say I have an array of time ranges like so:

[
  { name: 'A', startTime: '10:15', endTime: '11:15'},
  { name: 'B', startTime: '10:45', endTime: '14:15'},
  { name: 'C', startTime: '15:35', endTime: '16:15'},
  { name: 'D', startTime: '11:30', endTime: '16:20'},
  { name: 'E', startTime: '10:30', endTime: '18:00'},
]

which looks like this (visually):

|---A---|________________________________________________________________

_____|------B------|_____________________________________________________

________________________|----C----|______________________________________

___________|-----------D-----------|_____________________________________

___|-------------------E---------------------|___________________________

I wan't to arrange the intervals in a way that will result in an array of arrays so that:

  • Each interval of an array, does not intersect with ANY other interval in that array.

(Visual representation of what the end result might look like):

[
   [ A, D ],
   [ B, C ],
   [ E ]
]
  • The total number of arrays is absolutely the minimum number possible.

(by that I mean, if an element does intersect with the first array, but not the second array created, don't create a third array put it in the second one)

  • Performance is needed (The easiest way would be to iterate through every element to decide if it intersects, but that would be consuming resources like crazy) so something better than O(N^2) would be preferable.

Any ideas? Thank you.

SudoPlz
  • 20,996
  • 12
  • 82
  • 123
  • 1
    What about `[ A, C ]`? – Sani Huttunen Dec 07 '16 at 21:59
  • Could you please be more specific about what the output should be in general case? I don't get the "and another array, and another array, ..." part. – kraskevich Dec 07 '16 at 22:39
  • 1
    I think what he wants is for the given set of segments `S`, pick non-overlapping segments and put them in `A1`, then pick non-overlapping segments from `S-A1` and put them in `A2`, then pick non-overlapping segments from `S-A1-A2` and put them in `A3` and so on... However, I am not sure if he wants to pick the maximal number of non-overlapping segments in each iteration (any if multiple solutions exist) or minimize the total number of picked arrays. – Nikola Stojiljkovic Dec 07 '16 at 23:47
  • I changed the answer a bit @kraskevich, It might make more sense now. If not let me know I'll do my best to explain again. – SudoPlz Dec 08 '16 at 11:46

1 Answers1

1

you could do this:

  1. put the fist interval in set A0
  2. take the second interval. If it doesn't intersect intervals in a set, put it in such set, if it does consider the next set. if it intersects all sets, create a new one and put it there.

With a naive implementation of checking for interval intesection with set, this is O(N^2). However, for each set we can maintain a binary tree sorting intervals. Because intervals in a set do not intersect, there is a full ordering between them. This way, to check if an interval I intersects an interval in the tree, we can traverse the tree as follows:

  • if I intersects the current node N, return true
  • if I.right < N.left, move to the left child
  • if I.left > N.right, move to the right child

because we can traverse the tree in log(M) steps (where M is the size of the set, we get O(N x (N / M) x logM). If no interval overlaps, this is O(N x logN). If all intervals overlap, this becomes O(N x N). To further improve this worst case, you could organize the trees in a binary tree, Interval Tree or Augmented Tree (see https://en.wikipedia.org/wiki/Interval_tree), so that not all sets need to be traversed.

Roberto Attias
  • 1,883
  • 1
  • 11
  • 21
  • So what you're saying here is we sort intervals on separate arrays, by creating one interval tree for each new array we create, so that we can easily know if a new interval intersects any already existing in that array. Is that right? – SudoPlz Dec 08 '16 at 11:37
  • withing each array, an interval tree is not required; as all intervals are disjoint, a simple binary search tree is sufficient. in order to avoid scanning all existing arrays/binary trees when considering a new interval, you can organize those in a sort of interval tree. for example, for each array, you could maintain the min(left) and max(right), and create an interval tree using [min(left), max(right)] as intervals. if an interval I doesn't intersect [min(left), max(right)], then you can definitely add I to the latter. – Roberto Attias Dec 08 '16 at 18:54
  • However, you may also want to consider a different strategy where you just maintain the different arrays as binary trees, and when adding a new interval you traverse the list of arrays in random order. This may help balance across multiple trees (i.e., even if intervals are mostly disjoint, won't create a giant binary tree at the beginning and very small trees at the end of the list) – Roberto Attias Dec 08 '16 at 18:54