Как эффективно разделить набор интервалов (набор вход ) на минимальный набор непересекающихся интервалов (набор выход ) таким образом, чтобы все интервалы извходной набор может быть выражен в виде объединения интервалов из выходного набора?
Примеры:
Input: [0,9] [2,12]
Output: [0,1] [2,9] [10,12]
Test :
[0,9] = [0,1] ∪ [2,9]
[2,12] = [2,9] ∪ [10,12]
Input: [0,Infinity] [1,5] [4,6]
Output: [0,0] [1,3] [4,5] [6,6] [7,Infinity]
Test :
[0,Infinity] = [0,0] ∪ [1,3] ∪ [4,5] ∪ [6,6] ∪ [7,Infinity]
[1,5] = [1,3] ∪ [4,5]
[4,6] = [4,5] ∪ [6,6]
Мне нужно сделать это в Javascript.Вот идея, которую я попробовал:
// The input is an array of intervals, like [[0,9], [2,12]], same for the output
// This function converts a set of overlapping
// intervals into a set of disjoint intervals...
const disjoin = intervals => {
if(intervals.length < 2)
return intervals
const [first, ...rest] = intervals
// ...by recursively injecting each interval into
// an ordered set of disjoint intervals
return insert(first, disjoin(rest))
}
// This function inserts an interval [a,b] into
// an ordered set of disjoint intervals
const insert = ([a, b], intervals) => {
// First we "locate" a and b relative to the interval
// set (before, after, or index of the interval within the set
const pa = pos(a, intervals)
const pb = pos(b, intervals)
// Then we bruteforce all possibilities
if(pa === 'before' && pb === 'before')
return [[a, b], ...intervals]
if(pa === 'before' && pb === 'after')
// ...
if(pa === 'before' && typeof pb === 'number')
// ...
// ... all 6 possibilities
}
const first = intervals => intervals[0][0]
const last = intervals => intervals[intervals.length-1][1]
const pos = (n, intervals) => {
if(n < first(intervals))
return 'before'
if(n > last(intervals))
return 'after'
return intervals.findIndex(([a, b]) => a <= n && n <= b)
}
Но она очень неэффективна.В функции pos
я мог бы выполнить бинарный поиск, чтобы ускорить процесс, но я в основном задаюсь вопросом:
- Это известная проблема и имя в мире алгоритмов
- Существует оптимальное решение, которое не имеет ничего общего с тем, что я пробовал