Быстрый поиск наибольшей возрастающей подпоследовательности — различия между версиями
Shersh (обсуждение | вклад) м (→Псевдокод) |
м |
||
Строка 18: | Строка 18: | ||
* Если <tex>\pi(i)</tex> больше {{Acronym | <tex>\pi(1), \pi(2),~\dots~,\pi(i-1)</tex> | всех уже полученных значений B }}, значит с ним можно сделать максимальную, из уже рассмотренных, возрастающую подпоследовательность. Записываем его в конец <tex>B</tex> | * Если <tex>\pi(i)</tex> больше {{Acronym | <tex>\pi(1), \pi(2),~\dots~,\pi(i-1)</tex> | всех уже полученных значений B }}, значит с ним можно сделать максимальную, из уже рассмотренных, возрастающую подпоследовательность. Записываем его в конец <tex>B</tex> | ||
− | * Иначе <tex>\pi(i)</tex> | + | * Иначе <tex>\pi(i)</tex> заменяет наименьший лучший элемент, из тех, что больше <tex>\pi(i)</tex>. |
Следует отметить, что полученный массив также образует возрастающую последовательность, где мы должны выполнять операции <tex>insert, next, delete</tex>, соответственно целесообразно использовать [[ Приоритетные очереди | приоритетную очередь]], реализованную через [[Дерево ван Эмде Боаса]]. Таким образом получаем <tex>O(\operatorname{log}\operatorname{log} n)</tex> амортизированного времени на одну операцию. | Следует отметить, что полученный массив также образует возрастающую последовательность, где мы должны выполнять операции <tex>insert, next, delete</tex>, соответственно целесообразно использовать [[ Приоритетные очереди | приоритетную очередь]], реализованную через [[Дерево ван Эмде Боаса]]. Таким образом получаем <tex>O(\operatorname{log}\operatorname{log} n)</tex> амортизированного времени на одну операцию. | ||
Строка 67: | Строка 67: | ||
==== Псевдокод ==== | ==== Псевдокод ==== | ||
<code> | <code> | ||
− | ''' | + | '''int''' LIS('''vector<int>''' <tex>\pi</tex>) |
− | B | + | '''PriorityQueue''' B <font color=darkgreen>// рабочая приоритетная очередь</font> |
− | k = 0 <font color=darkgreen>// длина НВП</font> | + | '''int''' k = 0 <font color=darkgreen>// длина НВП</font> |
− | n = <tex>\pi</tex>.size | + | '''int''' n = <tex>\pi</tex>.size |
'''for''' i = 1 to n | '''for''' i = 1 to n | ||
x = <tex>\pi</tex>[i] | x = <tex>\pi</tex>[i] | ||
Строка 76: | Строка 76: | ||
<font color=darkgreen>// устаревшие будем удалять</font> | <font color=darkgreen>// устаревшие будем удалять</font> | ||
B.insert(x) | B.insert(x) | ||
− | '''if''' B.next(x) | + | '''if''' <tex>\exists</tex> B.next(x) |
<font color=darkgreen>// добавленный элемент — не максимальный</font> | <font color=darkgreen>// добавленный элемент — не максимальный</font> | ||
<font color=darkgreen>// удаляем предыдущее значение — заменяем {{Acronym |следующий|минимальный из бóльших}}</font> | <font color=darkgreen>// удаляем предыдущее значение — заменяем {{Acronym |следующий|минимальный из бóльших}}</font> | ||
Строка 132: | Строка 132: | ||
==== Псевдокод ==== | ==== Псевдокод ==== | ||
<code> | <code> | ||
− | ''' | + | '''vector<int>''' LIS('''vector<int>''' <tex>\pi</tex>) |
− | B | + | '''PriorityQueue''' B |
− | k = 0 | + | '''int''' k = 0 |
− | n = <tex>\pi</tex>.size | + | '''int''' n = <tex>\pi</tex>.size |
− | <font color=blue>predecessor | + | <font color=blue>'''vector<int>''' predecessor(n)</font> <font color=darkgreen>// резервируем <tex>n</tex> позиций</font> |
'''for''' i = 1 to n | '''for''' i = 1 to n | ||
x = <tex>\pi</tex>[i] | x = <tex>\pi</tex>[i] | ||
B.insert(x) | B.insert(x) | ||
<font color=blue>predecessor[x] = B.prev(x)</font> | <font color=blue>predecessor[x] = B.prev(x)</font> | ||
− | '''if''' B.next(x) | + | '''if''' <tex>\exists</tex> B.next(x) |
B.delete(B.next(x)) | B.delete(B.next(x)) | ||
'''else''' | '''else''' | ||
k = k + 1 | k = k + 1 | ||
− | <font color=darkgreen>//по цепочке от последнего элемента | + | <font color=darkgreen>// по цепочке от последнего элемента |
− | //восстанавливаем НВП</font> | + | // восстанавливаем НВП</font> |
− | <font color=blue>result | + | <font color=blue>'''vector<int>''' result |
− | cur = B.max() | + | '''int''' cur = B.max() |
result += [cur] | result += [cur] | ||
− | '''while''' predecessor[cur] | + | '''while''' <tex>\exists</tex> predecessor[cur] |
result += [predecessor[cur]] | result += [predecessor[cur]] | ||
cur = predecessor[cur] | cur = predecessor[cur] | ||
'''return''' result</font> | '''return''' result</font> | ||
</code> | </code> | ||
− | + | == Оптимизация до <tex>O(n\operatorname{log}\operatorname{log}k)</tex> == | |
− | == | + | === Деление на блоки === |
Версия 03:04, 6 января 2017
Эта статья находится в разработке!
Задача: |
Дана перестановка . Требуется найти НВП за , где — длина НВП. |
Содержание
Алгоритм
Нахождение длины НВП
Основная идея
Пусть
— входная перестановка.Для каждой длины элемент, что может быть последним в возрастающей подпоследовательности длины , запишем их в массив .
предполагаемой НВП находим наименьшийЕсли обрабатываемый элемент
больше последнего элемента какой-нибудь возрастающей последовательности, он может ее увеличить.Будем последовательно обрабатывать элементы
:- Если , значит с ним можно сделать максимальную, из уже рассмотренных, возрастающую подпоследовательность. Записываем его в конец больше
- Иначе заменяет наименьший лучший элемент, из тех, что больше .
Следует отметить, что полученный массив также образует возрастающую последовательность, где мы должны выполнять операции приоритетную очередь, реализованную через Дерево ван Эмде Боаса. Таким образом получаем амортизированного времени на одну операцию.
, соответственно целесообразно использоватьПример
Типы операций:
Последовательность:
9 | 3 | 10 | 4 | 8 | 1 | 2 | 12 | 6 | 5 | 7 | 11 |
Состояние очереди при каждом добавлении:
9 | 9 | ||||
3 | 3 | ||||
3 | 10 | 10 | |||
3 | 4 | 4 | |||
3 | 4 | 8 | 8 | ||
1 | 4 | 8 | 1 | ||
1 | 2 | 8 | 2 | ||
1 | 2 | 8 | 12 | 12 | |
1 | 2 | 6 | 12 | 6 | |
1 | 2 | 5 | 12 | 5 | |
1 | 2 | 5 | 7 | 7 | |
1 | 2 | 5 | 7 | 11 | 11 |
Псевдокод
int LIS(vector<int> следующий B.delete(B.next(x)) else // добавленный элемент - максимальный // предыдущие значения не трогаем, очередь увеличилась k = k + 1 return k) PriorityQueue B // рабочая приоритетная очередь int k = 0 // длина НВП int n = .size for i = 1 to n x = [i] // в любом случае добавляем в очередь очередной элемент // устаревшие будем удалять B.insert(x) if B.next(x) // добавленный элемент — не максимальный // удаляем предыдущее значение — заменяем
Расширение алгоритма до нахождения НВП
Основная идея
Будем запоминать пары: для каждого элемента записываем его "предшественника".
Тогда, выбрав какой-нибудь лучший элемент для максимальной длины, мы можем легко восстановить НВП .
Общий вид алгоритма
9 | 9 | ||||
3 | 3 | ||||
3 | 10 | 10 | |||
3 | 4 | 4 | |||
3 | 4 | 8 | 8 | ||
1 | 4 | 8 | 1 | ||
1 | 2 | 8 | 2 | ||
1 | 2 | 8 | 12 | 12 | |
1 | 2 | 6 | 12 | 6 | |
1 | 2 | 5 | 12 | 5 | |
1 | 2 | 5 | 7 | 7 | |
1 | 2 | 5 | 7 | 11 | 11 |
predecessor | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
1 | 3 | 2 | 2 | 5 | 4 | 3 | 7 | 8 |
Псевдокод
vector<int> LIS(vector<int>) PriorityQueue B int k = 0 int n = .size vector<int> predecessor(n) // резервируем позиций for i = 1 to n x = [i] B.insert(x) predecessor[x] = B.prev(x) if B.next(x) B.delete(B.next(x)) else k = k + 1 // по цепочке от последнего элемента // восстанавливаем НВП vector<int> result int cur = B.max() result += [cur] while predecessor[cur] result += [predecessor[cur]] cur = predecessor[cur] return result