Наибольшая общая подпоследовательность (LCS) двух последовательностей — самая длинная последовательность букв, которая встречается в обеих в том же порядке. Это основа утилит diff и сравнения ДНК.

Подпоследовательность и подстрока

  • Подстрока состоит из подряд идущих букв: "BCB" — подстрока "ABCBDAB".
  • Подпоследовательность сохраняет порядок, но буквы можно пропускать: "BCBA" — подпоследовательность "ABCBDAB".

Для X = "ABCBDAB" и Y = "BDCABA" длина LCS равна 4 (например, "BCBA").

Состояние и переход

  • Состояние: dp[i][j] — длина LCS первых i букв X и первых j букв Y.
  • База: dp[0][j] = dp[i][0] = 0.
  • Совпадение (X[i-1] == Y[j-1]): dp[i][j] = dp[i-1][j-1] + 1.
  • Несовпадение: dp[i][j] = max(dp[i-1][j], dp[i][j-1]), отбрасываем одну букву.
  • Ответ: dp[n][m].
Таблица LCS для "ABCBDAB" и "BDCABA" и путь восстановления
Таблица LCS для "ABCBDAB" и "BDCABA" и путь восстановления
python
def lcs_table(x, y):
    n, m = len(x), len(y)
    # dp[i][j]: LCS length of x[:i] and y[:j]
    dp = [[0] * (m + 1) for _ in range(n + 1)]
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            if x[i - 1] == y[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1              # match: extend
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])   # drop one letter
    return dp