5

I've been stumped on this algorithm for quite a bit.

Say there are four ranges of integers. Each range has a Start and an End value.

Range A: 0,5
Range B: 4,12
Range C: 2,10
Range D: 8,14

From these values I would like to get a new set which counts of the number of the ranges that fall in a particular span of ints. Each of these would have Start, End and Count values, producing something like this:

(Start, End, Count)
0,1,1   (Only 1 range (A) falls between 0 and 1 inclusive)
2,3,2   (2 ranges (A,C))
4,5,3   (3 ranges (A,B,C))
6,7,2   (2 ranges (B,C))
8,10,3  (3 ranges (B,C,D))
11,12,2 (2 ranges (B,D))
13,14,1 (1 range (D))

Does that make sense? What's a good way to approach the algorithm?

Sam Washburn
  • 1,817
  • 3
  • 25
  • 43
  • 1
    What algorithm you want will depend upon your use case - what is the maximum number of ranges you expect to deal with and the maximum range size? – Patashu Jun 16 '13 at 23:46
  • @Patashu Maximum number of ranges should be in the hundreds to low thousands, as would the range size. – Sam Washburn Jun 16 '13 at 23:49
  • 1
    If you don't need to remember which ranges cover which numbers, just the number of ranges that covered it, make an array with indexes 0...n where n is the largest max of any range, and for each range increment all elements of the array that it covers by 1. – Patashu Jun 16 '13 at 23:51
  • Here you go - http://jsfiddle.net/vsync/jrbb471h – vsync Mar 30 '16 at 14:28
  • @vsync Pretty cool. Though that was almost 3 years ago. I don't even remember what I was coding. Lol. – Sam Washburn Mar 30 '16 at 14:50
  • I'll post it as an answer. I am also wrapping my mind around this issue nowadays – vsync Mar 30 '16 at 14:53

3 Answers3

3

You can solve this in O(N ln N) time (for sorting) followed by the same amount of time for outputting results. If the number range is large, O(N ln N) is better than the O(M·N) time of the method suggested in a comment (where M = total range of numbers covered by the ranges).

Sort the N ranges into ascending order, keyed by Start value, say in array S. Initialize an empty priority queue P. Initialize a depth-count D to zero, and the current “reach” to R = S[0].Start.

While S[i].Start=R, push S[i].End on P and advance i and D. When S[i].Start>R, yield the tuple (R, p.top, D). Pop P to R and then decrease D by one and pop P while P.top==R.

Repeat the above paragraph while i<N.

James Waldby - jwpat7
  • 8,593
  • 2
  • 22
  • 37
1

const ranges = {
  A: [10, 12],
  B: [20, 30],
  C: [29, 31],
  D: [15, 95],
  E: [195, 196]
};

let overlaps = {},
    keys = Object.keys(ranges),
    values = Object.values(ranges),
    i, j;

for (i = 0; i < values.length; i++)
  for (j = 0; j < values.length; j++)
    if (keys[i] !== keys[j] &&           // skip same item
        values[i][0] < values[j][1] &&   // overlap check
        values[j][0] < values[i][1])     // overlap check
      overlaps[keys[i]] = 1;

console.log( Object.keys(overlaps) )
vsync
  • 118,978
  • 58
  • 307
  • 400
0

A range x intersects the input range y if:

x.End >= y.Start AND y.End >= x.Start

So, for a given input, just loop through your collection of ranges and see which satisfy the above condition.

If your given collection of ranges doesn't change very often, and your collection of ranges gets much larger than the 4 you stated in the problem description, then sort them first so that you can more efficiently search for the ranges that intersect your input, rather than looping through all of them.

If the given collection of ranges changes often, the sorting could be too expensive, and it would then be smarter to just loop through all of them each time.

mbeckish
  • 10,485
  • 5
  • 30
  • 55