token
@token

Конвертировать массив пересекающихся интервалов в массив не пересекающихся?

Привет эксперты!


Вопрос: имеется массив пересекающихся интервалов:

var ranges = [{<br/>
 &quot;from&quot;: 0,<br/>
 &quot;to&quot;: 100<br/>
}, {<br/>
 &quot;from&quot;: 50,<br/>
 &quot;to&quot;: 200<br/>
}, {<br/>
 &quot;from&quot;: 0,<br/>
 &quot;to&quot;: 100<br/>
}, {<br/>
 &quot;from&quot;: 70,<br/>
 &quot;to&quot;: 200<br/>
}, {<br/>
 &quot;from&quot;: 90,<br/>
 &quot;to&quot;: 300<br/>
}];



Мне необходимо сконвертировать его в массив не пересекающихся интервалов, т. е.:

var nonOverlapping = splitRanges(ranges);<br/>
<br/>
/*<br/>
nonOverlapping = [{<br/>
 &quot;from&quot;: 0,<br/>
 &quot;to&quot;: 49<br/>
}, {<br/>
 &quot;from&quot;: 50,<br/>
 &quot;to&quot;: 69<br/>
}, {<br/>
 &quot;from&quot;: 70,<br/>
 &quot;to&quot;: 89<br/>
}, {<br/>
 &quot;from&quot;: 90,<br/>
 &quot;to&quot;: 100<br/>
}, {<br/>
 &quot;from&quot;: 101,<br/>
 &quot;to&quot;: 200<br/>
}, {<br/>
 &quot;from&quot;: 201,<br/>
 &quot;to&quot;: 300<br/>
}]<br/>
*/



У меня есть функция которая выполняет это, но использует она так называемый «naive approach» (крайне неэффективное решение):

function splitRanges(ranges) {<br/>
 var repeat, length, i, j;<br/>
 var rangeA, rangeB, intersection;<br/>
 do {<br/>
 repeat = false;<br/>
 length = ranges.length;<br/>
 for (i = 0; i &lt; length; i++) {<br/>
 rangeA = ranges[i];<br/>
 for (j = i + 1; j &lt; length; j++) {<br/>
 rangeB = ranges[j];<br/>
 if (isIntersectingRanges(rangeA, rangeB)) {<br/>
 repeat = true;<br/>
 ranges.splice(i, 1);<br/>
 intersection = splitRange(rangeA, rangeB);<br/>
 while (intersection.length) {<br/>
 ranges.push(intersection.shift());<br/>
 }<br/>
 }<br/>
 if (repeat) break;<br/>
 }<br/>
 if (repeat) break;<br/>
 }<br/>
 } while (repeat);<br/>
}



Мог бы кто — нибудь помочь мне переписать это так чтобы решение было оптимальным с точки зрения быстродействия?
  • Вопрос задан
  • 2709 просмотров
Пригласить эксперта
Ответы на вопрос 1
VladX
@VladX
Складываете все численные значения from и to в один массив, при этом в этом массиве должны лежать пары (граница, тип), где тип — это значение типа boolean (например, true — это левая граница (from), а false — правая (to)).
Затем запускаете алгоритм быстрой сортировки на массиве.
Затем, FOR-ом проходите по отсортированному массиву и формируете окончательный список. Список формируется примерно так: проверяем тип границы, добавляем границу в список, идём дальше. Если несколько раз подряд встречается граница одного типа, то имеет место пересечение. В этом случае для левой границы нужно запоминать только первый встретившийся элемент, а для правой — последний.
Вот как-то так. Если не понятно объяснил, спрашивайте.

Алгоритм работает примерно за O(N log(N) + N) = O(N log(N)), т.е. довольно быстро.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы