2010-07-09 3 views
2

Я не буду вдаваться в подробности проблемы, которую я пытаюсь решить, но она имеет дело с большой строкой и включает в себя поиск перекрывающихся интервалов, существующих в строке. Я могу использовать только один из интервалов, которые перекрываются, поэтому я хотел отделить эти интервалы и проанализировать их по отдельности. Мне было интересно, какой алгоритм использовать, чтобы сделать это максимально эффективно.Эффективный алгоритм для нахождения перекрытий строк

Я должен подчеркнуть, что здесь важна скорость. Мне нужно как можно быстрее отделить интервалы. Алгоритм, который пришел мне на ум, был Деревом Интервала, но я не был уверен, что это лучшее, что мы можем сделать.

Интервал Деревья могут быть запрошены в O (log n), n - количество интервалов, а для построения требуется O (nlog n) время, хотя я хотел знать, можем ли мы срубить их.

Спасибо!

Редактировать: Я знаю, вопрос неопределенный. Прошу прощения за путаницу. Я предлагаю, чтобы люди смотрели на ответ Аарона Хурана и комментарии к ним. Это должно помочь прояснить ситуацию намного больше.

+1

Что вы имеете в виду под «перекрывающихся интервалов в строке»? –

+0

Строка: «ThisIsATestStringToShowWhatIMeanByIntervals» Интервалы: 0-4, 5-13, 8-19, 10-12 Здесь интервалы 5-13, 8-19 и 10-12 перекрываются, и поэтому я могу использовать только один из их. – efficiencyIsBliss

+0

Являются ли интервалы всегда отсортированными по начальной точке? – Triptych

ответ

1

Ну, мне было скучно прошлой ночью, поэтому я сделал это на Python. Это рекурсивно без необходимости (я только что прочитал The Little Schemer и думаю, что рекурсия супер аккуратная прямо сейчас), но она решает вашу проблему и обрабатывает все входные данные, которые я выбрал.

intervals = [(0,4), (5,13), (8,19), (10,12)] 

def overlaps(x,y): 
    x1, x2 = x 
    y1, y2 = y 
    return ( 
     (x1 <= y1 <= x2) or 
     (x1 <= y2 <= x2) or 
     (y1 <= x1 <= y2) or 
     (y1 <= x2 <= y2) 
    ) 

def find_overlaps(intervals, checklist=None, pending=None): 
    if not intervals: 
     return [] 

    interval = intervals.pop() 

    if not checklist: 
     return find_overlaps(intervals, [interval], [interval]) 

    check = checklist.pop() 

    if overlaps(interval, check): 
     pending = pending or [] 
     checklist.append(check) 
     checklist.append(interval) 
     return pending + [interval] + find_overlaps(intervals, checklist) 
    else: 
     intervals.append(interval) 
     return find_overlaps(intervals, checklist) 

Использование так:

>>> find_overlaps(intervals) 
[(10, 12), (8, 19), (5, 13)] 

Обратите внимание, что он возвращает все перекрывающиеся интервалы в порядке, обратном порядку их начальной точки. Надеюсь, это второстепенная проблема. Это происходит только потому, что я использую push() и pop() в списке, который работает в конце списка, а не insert(0) и pop(0), который работает в начале.

Это не идеально, но оно работает в линейном времени. Также помните, что размер фактической строки вообще не имеет значения - время работы зависит от количества интервалов, а не от размера строки.

+0

Да, я знаю, что длина строки не имеет значения. Я также реализовал нечто подобное в линейном времени, но я надеялся, что смогу сделать что-то лучше. Я думаю, что интервальные деревья могут привести нас к O (log n), хотя я еще не прочитал их правильно. – efficiencyIsBliss

+0

Что такое функция 'g'? Вы что-то оставили по ошибке или это какой-то встроенный Python (которого я не могу найти в Интернете)? – Lii

+0

Я думаю, что это на самом деле * O (n^2) * в количестве перекрывающихся интервалов, так как на каждой итерации вы копируете все ранее найденные элементы в новый список вместе с недавно найденным. Кроме того, я полагаю, вы зависеть от заранее отсортированных интервалов, что равно * O (n log n) *. – Lii

1

Вы хотите рассчитать разницу между двумя строками вправо? На каком языке вы пытаетесь это сделать?

Обновление: Без каких-либо критериев, как вы будете выбирать, какие интервалы использовать, есть огромные возможные решения.

Одним из способов было бы принять наименьшее начальное число, захватить его конец. Захватите следующий стартовый номер, который больше, чем конец предыдущего интервала. Получить конец этого интервала и повторить.

Итак, для 0-4, 5-13, 8-19, 10-12 Вы получаете: 0-4, 5-13 и игнорируете остальные.

+0

Я использую Java, но я не хочу рассчитать разницу между двумя строками. У меня есть только одна строка, в которой есть несколько интервалов. Мне нужно использовать эти интервалы для некоторых вычислений, но я могу использовать только один из всех перекрывающихся интервалов, поэтому я хочу их разделить. – efficiencyIsBliss

+0

@Dharmesh: Что вы подразумеваете под «несколькими интервалами, определенными в нем»? Вы пытаетесь разобрать формат данных? Если да, можете ли вы предоставить некоторый ввод проб? –

+0

Я привязал оценки к строковым интервалам, и мне нужен тот, у которого самый высокий балл. Таким образом, может быть, что интервал 10-12 имеет наивысший балл, но если мы будем использовать метод, описанный выше, мы будем иметь время работы O (n). – efficiencyIsBliss

Смежные вопросы