На днях столкнулся с задачей, где при обработке строки мне приходится вычислять минимальный период (длина периода делит длину строки) для каждой ее подстроки. Возможно ли это как-то делать за O(N^2) или хотя бы просто быстрее, чем за O(N^3)?
UPD: Ночью я хорошо поспал, поэтому, проснувшись, я вроде как нашел решение. Буду рад, если его кто-нибудь проверит:
- Для каждого префикса
P
исходной строкиS
будем считать ДП по длинеi - j + 1
его суффиксаS[j..i]
. - Пусть мы нашли минимальный период подстроки
S[j..i]
, который равенp = dp[j][i]
. Тогда предположим, что этот же период будет и у подстрокиS[j-p..i]
. Чтобы проверить наше предположение нужно только проверить равенство подстрокS[j-p..j-1]
иS[j..j+p-1]
, что можно сделать с помощью хэшей за O(1).
def is_eq_substr(beg1, end1, beg2, end2):
# Тут должен быть код для хешей, но писать хеши на питоне - себя не любить, так что я просто поставлю заглушку
global S
return S[beg1:end1+1] == S[beg2:end2+1]
S = 'ababab'
n = len(S)
dp = [[i - j + 1 for i in range(n)] for j in range(n)]
for i in range(n):
for j in range(i, -1, -1):
p = dp[j][i]
if j - dp[j][i] >= 0 and is_eq_substr(j - p, j - 1, j, j + p - 1):
dp[j - p][i] = p # min() использовать не нужно, так как dp[j - p][i] = i - (j - p) + 1
# или dp[j - p][i] = dp[j - p + p1][i] = p1, где p1 - p > 0, а значит p1 > p
for i in range(n):
print(' '.join([str(dp[j][i]) for j in range(i + 1)]))
Решим задачу для всех префиксов строки: Пройдем по всем символам слева направо О(н), переберем все делители длины О(корня), проверим хешами, что это период (константа), ещё умножим на на О(н) для перебора первого символа
А хешами можно за O(1) проверять равенство сразу O(N) последовательных подстрок? Или смысл такой же, как я сейчас написал в посте?
Нужно только одно сравнение строк(префикс и суффикс длина n-t)
Спасибо. Очень красивый способ.
Подумайте как по префиксфункция даёт кратчайший период и получится решение за квадрат.
Период либо n-pi(n-1) либо n, если я все правильно понимаю
Автокомментарий: текст был обновлен пользователем EzikBro (предыдущая версия, новая версия, сравнить).
Автокомментарий: текст был обновлен пользователем EzikBro (предыдущая версия, новая версия, сравнить).