Найти период каждой подстроки за O(N^2)

Revision ru3, by EzikBro, 2021-03-07 09:35:35

На днях столкнулся с задачей, где при обработке строки мне приходится вычислять минимальный период (длина периода делит длину строки) для каждой ее подстроки. Возможно ли это как-то делать за 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)]))

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
ru3 Russian EzikBro 2021-03-07 09:35:35 179 Мелкая правка: ' - p) + 1 или dp[j ' -> ' - p) + 1 \n # или dp[j '
ru2 Russian EzikBro 2021-03-07 09:22:46 1133 Мелкая правка: 'n\n~~~~~\n\n~~~~~\n\' -> 'n\n~~~~~\nint main()\n{\n}\n~~~~~\n\'
ru1 Russian EzikBro 2021-03-06 23:30:37 280 Первая редакция (опубликовано)