Изменения
Нет описания правки
== Динамическое программирование ==
=== Решение ===
Обозначим как <mathtex>a_{i, j}</mathteh> НОП префиксов данных последовательностей, заканчивающихся в элементах с номерами <mathtex>i</mathtex> и <mathtex>j</mathtex> соответственно.Получаем следующее рекуррентное соотношение:*<mathtex>a_{i, j} = a_{i - 1, j - 1} + 1</mathtex>, если <mathtex>s[i] = s[j]</mathtex> (соответствующие элементы последовательностей равны)*<mathtex>a_{i, j} = max(a_{i, j - 1}, a_{i - 1, j})</mathtex>, если <mathtex>s1[i] <> s2[j]</mathtex> (соответствующие элементы последовательностей не равны).Очевидно, что сложность алгоритма составит <mathtex>O(n^2)</mathtex>.
=== Доказательство оптимальности ===
Предположим, что некоторое значение <mathtex>a_{i, j}</mathtex> посчитано неверно. Однако, в случае различия соответствующих символов, они не могут одновременно участвовать в НОП, а значит ответ действительно равен формуле для случая с различными символами. В случае же равенства, ответ не может быть больше, чем <mathtex>a_{i - 1, j - 1} + 1</mathtex>, так как тогда неверно посчитано значение <mathtex>a_{i - 1, j - 1} + 1</mathtex>.
=== Построение подпоследовательности ===
=== Пример реализации на Java ===
public int[] lcs(int[] s1, int[] s2) {
int[][] a = new int[s1.length][s2.length];
//Подсчет значений
for (int i = 0; i < s1.length; i++)
if ((i == 0) || (j == 0)) {
a[i][j] = 1;
} else {
a[i][j] = a[i - 1][j - 1] + 1;
}
else {
if ((i > 0) && (a[i - 1][j] > a[i][j])) {
a[i][j] = a[i - 1][j];
}
if ((j > 0) && (a[i][j - 1] > a[i][j])) {
a[i][j] = a[i][j - 1];
}
}
}
}