На днях столкнулся с задачей, где при обработке строки мне приходится вычислять минимальный период (длина периода делит длину строки) для каждой ее подстроки. Возможно ли это как-то делать за O(N^2) или хотя бы просто быстрее, чем за O(N^3)?↵
↵
UPD: ↵
Ночью я хорошо поспал, поэтому, проснувшись, я вроде как нашел решение. Буду рад, если его кто-нибудь проверит:↵
↵
1. Для каждого префикса `P` исходной строки `S` будем считать ДП по длине `i - j + 1` его суффикса `S[j..i]`.↵
2. Пусть мы нашли минимальный период подстроки `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)]))↵
~~~~~↵
↵
↵
UPD: ↵
Ночью я хорошо поспал, поэтому, проснувшись, я вроде как нашел решение. Буду рад, если его кто-нибудь проверит:↵
↵
1. Для каждого префикса `P` исходной строки `S` будем считать ДП по длине `i - j + 1` его суффикса `S[j..i]`.↵
2. Пусть мы нашли минимальный период подстроки `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)]))↵
~~~~~↵
↵