Самая длинная неперекрывающаяся подстрока - PullRequest
5 голосов
/ 24 августа 2009

Интересно, знает ли кто-нибудь (оптимальный?) Алгоритм для самой длинной повторяющейся непересекающейся подстроки.

Например, в строке

ABADZEDGBADEZ

самый длинный повторяющийся будет "ПЛОХО". Кстати, если такого результата нет, алгоритм должен предупредить, что такая вещь произошла. Я предполагаю, что это связано с деревьями суффиксов.

Я уверен, что это должно уже где-то существовать. Спасибо за помощь!

Ответы [ 4 ]

4 голосов
/ 24 августа 2009

Суффиксный массив - хорошая структура данных для решения этой проблемы.

Решение этой проблемы есть в Программирование жемчуга Джона Бентли.

4 голосов
/ 24 августа 2009

Поскольку вы применяете это к музыке, вы, вероятно, не ищете 100% совпадений; будут ожидаемые различия от одного экземпляра темы к другому. Вы можете попробовать поискать алгоритмы анализа последовательности генов - там происходит множество всего этого. Попробуйте BLAST или другие алгоритмы выравнивания.

Вы также можете попробовать семейство алгоритмов WinEPI, а также различные реализации дерева префиксов этого конкретного набора результатов (эти результаты допускают пробелы в подстроке; например, ABCID и AFBCD содержат ABCD). На самом деле у меня есть статья об алгоритме, на которую стоит взглянуть, если вам будет интересно; Мне нужно получить разрешение на распространение, поэтому дайте мне знать.

Обратите внимание, что на самом деле это ОЧЕНЬ сложная тема (для эффективного выполнения) для больших наборов данных.

Источник: Исследования в течение года или двух по сопоставимой теме (определение темы).

1 голос
/ 24 августа 2009

Простой алгоритм заключается в следующем:

  • Создать структуру данных, представляющую фрагменты строки; реализовать сравнение / сортировку в зависимости от языка
  • Создать список каждого фрагмента строки, начиная с [первый символ, последний символ], [второй символ, последний символ], вплоть до [последний символ, последний символ]
  • Сортировать этот список - O (n log n)
  • Это объединяет все строковые фрагменты с общими префиксами. Затем вы можете выполнить итерацию по списку, сравнивая каждую пару, чтобы увидеть, сколько символов они разделяют в начале, и если он больше вашего максимума, запишите его и установите в качестве нового максимума

(Как показывает только что опубликованный ответ, я здесь описываю массив суффиксов.)

0 голосов
/ 25 августа 2009

Хорошо, вот одна безумная идея.

Создать функцию, которая определяет, есть ли повторяющаяся подстрока длины k в O (n) (где n - длина текста). Это можно сделать с помощью скользящего хэша (см. Википедию Алгоритм согласования строк Рабина-Карпа ) для генерации всех n хешей за линейное время и использования хеш-таблицы / BST (или карты или dict или любого другого языка называет это), чтобы сохранить соответствующие позиции подстроки. Прежде чем вставить текущий хеш в структуру данных, мы проверяем, видели ли мы его раньше. Если это было замечено ранее, мы просто ищем индексы, где этот хеш был сгенерирован, и видим, является ли соответствующая подстрока неперекрывающимся соответствием.

Теперь, когда мы можем найти подстроку длины k за O (n), мы просто запускаем двоичный поиск, чтобы найти наибольшее k, для которого мы можем найти неперекрывающееся совпадение подстроки, используя нашу функцию.

Код в Python следует

A=23
MOD=10007 # use a random value in the real world

def hsh(text):
    return sum([ord(c)*A**(len(text)-i-1) for i,c in enumerate(text)])%MOD

def k_substring(text, k):
    substrings={}
    cur=hsh(text[:k])
    pwr=(A**(k-1))%MOD
    substrings[cur]=[0]
    for i in xrange(k,len(text)):
        to_remove=(ord(text[i-k])*pwr)%MOD
        to_add=ord(text[i])
        cur-=to_remove
        if cur<0:
            cur+=MOD
        cur=(cur*A)%MOD
        cur=(cur+to_add)%MOD
        if cur in substrings:
            lst=substrings[cur]
            for index in lst:
                if index+k<=i-k+1 and text[index:index+k]==text[i-k+1:i+1]:
                    return index
            lst.append(i-k+1)
        else:
            substrings[cur]=[i-k+1]
    return -1

def longest_substring(text):
    hi,lo=len(text),0
    while hi>lo:
        mid=(hi+lo+1)>>1
        if k_substring(text,mid)==-1:
            hi=mid-1
        else:
            lo=mid
    index=k_substring(text,lo)
    return text[index:index+lo]

(Извините, если это неясно. Сейчас 6:30 утра, и мне действительно нужно вернуться в постель :))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...