Количество вхождений подстрок в строку в O(N)

Мне было интересно, как посчитать количество вхождений каждой иглы в стоге сена за линейное время. Я думал, что буду использовать алгоритм Aho-Corasick, но я не хочу, чтобы сложность времени зависела от количества попаданий игл.

2 ответа

Используйте Rabin–Karp, если вы хотите найти набор строк и не хотите зависеть от количества вхождений. Его среднее / лучшее время выполнения O(n + m), но его худшее время O(нм), где n длина текста и m комбинированная длина шаблонов поиска.

Если вы хотите искать только одну строку, вы можете использовать Кнут-Моррис-Пратт со сложностью O(n + k), где n длина текста и k длина шаблона поиска.

Если вам нужно только общее количество вхождений (и вам самим нет дела до позиций), вы можете эффективно использовать Aho-Corasick. Давайте предположим, что мы в данный момент находимся в узле v, Сколько подстрок заканчивается в текущей позиции. Я утверждаю, что это точно количество терминальных узлов, достижимых из v по суффиксным ссылкам. Но суффиксные ссылки образуют дерево. Таким образом, нам нужно посчитать количество конечных вершин на пути от v к корню в дереве, образованном суффиксными ссылками. Мы можем сделать это в O(1) время с линейной предварительной обработкой (например, можно построить это дерево в явном виде и вычислить сумму на пути от корня до любой вершины за линейное время, используя один поиск в глубину). Мы также можем обработать вершины в правильном порядке (например, в порядке увеличения высоты) и сделать что-то вроде sum[v] += sum[suffix_link(v)], В этом случае нам даже не нужно создавать это дерево.

Этот алгоритм четко работает за линейное время с размером входных данных (мы строим автомат Aho-Corasick и вычисляем сумму по "путям суффиксных связей" за линейное время, а затем используем автомат, как мы обычно это делаем).

Другие вопросы по тегам