Количество подпалиндромов в строке — различия между версиями
Строка 26: | Строка 26: | ||
ans += binarySearch(s, i, 0) + binarySearch(s, i, 1) | ans += binarySearch(s, i, 0) + binarySearch(s, i, 1) | ||
'''return''' ans | '''return''' ans | ||
+ | === Избавление от коллизий === | ||
+ | Проверять две подстроки на совпадение можно с помощью суффиксного массива. Для этого построим суффиксный массив для строки <tex>s + "\#" + reverse(s)</tex>, при этом сохраним промежуточные результаты классов эквивалентности <tex>c</tex>. Пусть нам требуется проверить на совпадение подстроки <tex>s[i..i + l]</tex> и <tex>s[j..j + l]</tex>. Разобьем каждую нашу строку на две пересекающиеся подстроки длиной <tex>2^k</tex>, где <tex>k = \lfloor \log{l} \rfloor</tex>. Тогда наши строки совпадают, если <tex>c[k][i] = c[k][j]</tex> и <tex>c[k][i + l - 2^k] = c[k][j + l - 2^k]</tex>. | ||
+ | |||
+ | Итоговая асимптотика алгоритма: предподсчет за построение суффиксного массива и <tex>O(\log(|s|)</tex> на запрос, если предподсчитать все <tex>k</tex>, то <tex>O(1)</tex>. | ||
==См. также== | ==См. также== |
Версия 13:25, 27 марта 2016
Определение: |
Палиндромом (англ. Palindrome) называется строка, которая одинаково читается как слева направо, так и справа налево. |
Задача: |
Пусть дана строка | , требуется посчитать количество подпалиндромов в ней за .
Алгоритм
Идея
Для каждой позиции в строке
найдем длину наибольшего палиндрома с центром в этой позиции. Длину палиндрома будем искать бинарным поиском. Для сохранения асимптотики проверку совпадения левой и правой половины требуется выполнить за . Для этого можно воспользоваться методом хеширования.Псевдокод
int binarySearch(s : string, center, shift : int): //shift = 0 при поиске палиндрома нечетной длины, иначе shift = 1 int l = -1, r = s.length, m = 0 while r - l != 1 m = l + (r - l) / 2 if hash(s[center - m..center]) == hash(reverse(s[center + shift..center + shift + m])) l = m else r = m return r
int palindromesCount(s : string): int ans = 0 for i = 0 to s.length ans += binarySearch(s, i, 0) + binarySearch(s, i, 1) return ans
Избавление от коллизий
Проверять две подстроки на совпадение можно с помощью суффиксного массива. Для этого построим суффиксный массив для строки
, при этом сохраним промежуточные результаты классов эквивалентности . Пусть нам требуется проверить на совпадение подстроки и . Разобьем каждую нашу строку на две пересекающиеся подстроки длиной , где . Тогда наши строки совпадают, если и .Итоговая асимптотика алгоритма: предподсчет за построение суффиксного массива и
на запрос, если предподсчитать все , то .