Algorithm to find the maximum sum in a sequence of overlapping intervals
Solution 1:
This is a weighted variation of interval scheduling; it's solvable in O(N log N)
with dynamic programming.
Let an interval be g(start, stop, score)
, and let them be sorted by stop
. For simplicity, let's assume for now that all stop
is unique.
Let best[i]
be the best score we can get when we're allowed to use g[1], ..., g[i]
. We don't have to use them all, of course, and generally we can't because the subset of intervals we use must be non-overlapping.
- Clearly
best[0] = 0
. That is, since we can't use any interval, the best score we can get is 0. - For any
1 <= k <= N
, we have:-
best[k] = max( best[k-1], best[j] + g[k].score )
, where-
j
is the largest index such thatg[j].stop < g[k].start
(j
may be zero)
-
-
That is, given that we're allowed to use g[1], ... g[k]
, the best we can do is the better scoring of these two options:
- We do not include
g[k]
. Thus, the score of this option isbest[k-1]
.- ... because that's the best we can do with
g[1], ... g[k-1]
- ... because that's the best we can do with
- We include
g[k]
, and to its left we do the best we can with all the genes that don't overlap withg[k]
, i.e. allg[1], ..., g[j]
, whereg[j].stop < g[k].start
andj
is as large as possible. Thus, the score of this option isbest[j] + g[k].score
.
(Note the optimal substructure and overlapping subproblems components of dynamic programming embodied in the above equation).
The overall answer to the question is best[N]
, i.e. the best score we can get when we're allowed to use all the genes. Oops, did I say genes? I mean intervals.
This is O(N log N)
because:
- Sorting all the intervals takes
O(N log N)
- Finding
j
for eachk
isO(log N)
using binary search
If several genes can have the same stop
values, then nothing changed: you still have to search for the rightmost j
. In e.g. Python this is easy with bisect_right
. In Java where the standard library binary search doesn't guarantee which index is returned in case of ties, you can (among many options) follow it with a linear search (for O(N)
worst-case performance), or another series of binary searches to find the right most index.
Oops did I say genes again? I mean intervals.
Related questions
- Extension of binary search to find the first and last index of the key value
Solution 2:
First of all, I think the maximum is 59, not 55. If you choose intervals [0-5],[8-21], and [25,30], you get 15+19+25=59. You can use some sort of dynamic programming to handle this.
First, you sort all the intervals by their starting point, then iterate from end to start. For each item in list, you choose the maximum sum from that point to the last as max(S[i]+S[j], S[i+1])
, where i is the item you are on, j is the item that is the first non-overlapping entry following your item (that is, the first item whose start is larger than the current item's end). To speed up the algorithm, you want to store the maximum partial sum S[j] for each element.
To clarify, let me solve your example according to this. First, sort your intervals:
1: 0- 5 - 15
2: 4- 9 - 18
3: 8-21 - 19
4: 10-15 - 12
5: 25-30 - 25
So,
S[5] = 25
S[4] = max(12+S[5], 25)=37
S[3] = max(19+S[5], S[4])=max(19+25,37)=44
S[2] = max(18+S[4], S[3])=max(18+37,44)=55
S[1] = max(15+S[3], S[2])=max(15+44, 55)=59
This is an adaptation of the algorithm in this post, but unfortunately, doesn't have the nice O(n) running time. A degenerate list where each entry overlaps the next would cause it to be O(n^2).