Интервал установлен в Java
У меня есть список интервалов с целочисленными значениями [например. [1, 4], [10, 19] и т. Д.]. Есть ли способ поместить эти интервалы в контейнер некоторых коллекций Java [например. Установить] таким образом, чтобы я мог вызвать функцию 'union' для контейнера. Функция 'union' должна выдавать мне список интервалов, так что если любые 2 вставленных интервала перекрываются, то они должны быть объединены в выходных данных. Я попытался использовать класс Range в Guava, но в итоге сравнил все интервалы друг с другом перед слиянием. Элегантный подход к этому был бы по достоинству оценен! Вот что я попробовал, основываясь на ответе ниже. Выходные данные [[1, 15], [17, 20]], что правильно. Я хотел знать, есть ли какой-нибудь API, который реализует что-то вроде этого.
public static void main(String[] args) {
// mock data
List<MyIntRange> rng_lst = new ArrayList<Junk.MyIntRange>();
rng_lst.add(new MyIntRange(1, 10));
rng_lst.add(new MyIntRange(5, 15));
rng_lst.add(new MyIntRange(17, 20));
// sort intervals by start position
Collections.sort(rng_lst);
// merge the intervals which overlap
List<MyIntRange> res_lst = new ArrayList<Junk.MyIntRange>();
MyIntRange old_rng = null;
for (MyIntRange cur_rng : rng_lst) {
if (old_rng == null) {
old_rng = cur_rng;
} else {
if (old_rng.rng.upperEndpoint() < cur_rng.rng.lowerEndpoint()) {
// this does not over lap with the next one
res_lst.add(old_rng);
old_rng = cur_rng;
} else {
// overlap
old_rng = new MyIntRange(old_rng.rng.lowerEndpoint(),
cur_rng.rng.upperEndpoint());
}
}
}
// add the last range
res_lst.add(old_rng);
// done!
System.out.println(res_lst);
}
// wrapper around Guava's Range to make it comparable based on the
// interval's start
public static class MyIntRange implements Comparable<MyIntRange> {
Range<Integer> rng;
public MyIntRange(int start, int end) {
rng = Ranges.closed(start, end);
}
public int compareTo(MyIntRange that) {
int res = -1;
if (this.rng.lowerEndpoint() > that.rng.lowerEndpoint()) {
res = 1;
}
return res;
}
public String toString() {
return "[" + rng.lowerEndpoint() + ", " + rng.upperEndpoint() + "]";
}
}
Спасибо
2 ответа
Это в основном именно то, что RangeSet
в только что выпущенном Guava 14.0, за исключением того, что он выполняет слияние для вас, вместо того, чтобы сообщать вам, какие диапазоны могут быть объединены.
Основной алгоритм:
- Сортировать интервалы по стартовому индексу
- Пройдите по списку. Для
i
ая вещь:- Сравните конечный индекс
i
с начальным индексом(i+1)
ст. - Если конечный индекс больше, установите конечный индекс
i
до конца индексаi+1
и удалитеi+1
элемент. (Это объединяет их.)
- Сравните конечный индекс
Сложность времени: O(nlgn)
из-за первоначальной сортировки. (То есть, если удаление сделано правильно.)