Динамическое программирование (dynamic programming, DP) — мощный инструмент для решения определенного класса задач. Идея очень проста: если вы решили задачу для каких-то вводных данных, сохраните этот результат для будущих вычислений, чтобы снова не решать ту же самую задачу с теми же данными.
Запомните! «Кто не помнит своего прошлого, обречен на то, чтобы пережить его вновь»
Сверху-вниз: Начните с разбиения задачи на подзадачи. Если вы видите, что подзадача уже была решена, тогда используйте сохраненный ранее результат. Иначе решите подзадачу и сохраните её результат. Эта техника интуитивно понятна и называется мемоизацией.
Снизу-вверх: Проанализируйте задачу и определите порядок, в котором решаются подзадачи, и начните решать от тривиальной подзадачи до изначальной задачи. Это гарантирует, что подзадачи будут решены, прежде чем решится вся задача. В этом и заключается динамическое программирование.
В задаче по определению самой длинной возрастающей подпоследовательности необходимо найти найти самую длинную возрастающую подпоследовательность для заданной последовательности.
Для последовательности S={ a1, a2, a3, a4, ............., an-1, an } мы должны найти самое длинное подмножество, такое, что для всех j и i, j<i в подмножестве aj<ai.
Прежде всего, мы должны найти значение самых длинных подпоследовательностей (LSi) для каждого индекса i с последним элементом последовательности, равным ai. Тогда наибольшая LSi будет самой длинной подпоследовательностью в данной последовательности. Для начала LSi равна единице, поскольку ai является элементом последовательности (последний элемент). Затем для всех j таких, что j<i и aj<ai, мы находим наибольшую LSj и добавляем ее к LSi. Тогда алгоритм выполняется за O(n2).
Псевдокод для определения длины самой длинной возрастающей подпоследовательности:
сложность этого алгоритма можно уменьшить, если использовать структуру данных получше, а не массив. Использование массива с предшественниками и переменной largest_sequences_so_far («наибольшие последовательности на данный момент») и ее индекса сэкономит много времени.
Аналогичная концепция может быть применена для определения самого длинного пути в направленном ациклическом графе.
for i=0 to n-1
LS[i]=1
for j=0 to i-1
if (a[i] > a[j] and LS[i]<LS[j])
LS[i] = LS[j]+1
for i=0 to n-1
if (largest < LS[i])
Хотите предложить свой перевод? Может быть, улучшение перевода? Откройте Issue в репозитории GitHub или сделайте pull request сами!
Первоначально предоставлено автором Akashdeep Goel, и обновлено 1 автором.