Для заданной последовательности
найдите длину наибольшей строго возрастающей подпоследовательности.
Вход. Первая строка содержит длину n (1 ≤ n ≤
1000) последовательности. Вторая строка содержит саму последовательность. Числа
последовательности – целые числа, не превосходящие 104 по модулю.
Выход. Выведите длину наибольшей
строго возрастающей подпоследовательности.
Пример
входа |
Пример
выхода |
6 3 29 5 5 28
6 |
3 |
наибольшая
возрастающая подпоследовательность
Анализ алгоритма
Решение за O(n2). В задаче следует
найти длину наибольшей возрастающей подпоследовательности (НВП) для последовательности x0, x1, …,
xn-1.
Объявим массив lis, где lis[i]
содержит длину НВП, которую можно выделить среди чисел x0,
x1, …, xi, и которая обязательно заканчивается элементом xi. Если массив x содержит n чисел, то
ответом задачи будет наибольшее среди чисел lis0, …, lisn-1. Значение lis0 положим равным 1: НВП для последовательности из одного элемента равна
этому самому элементу. Следующие значения массива lis вычисляются согласно
соотношению:
Элемент xi может продолжить только те НВП, которые заканчиваются
элементом xj, для которого j < i и xj < xi.
Решение за O(n log2n). После обработки i элементов
массива x хвост массива
lis (ячейки от lisk до lislen-1
для некоторого k) содержит хвост наибольшей возрастающей подпоследовательности,
которую можно выделить среди чисел x0, x1, …, xi. При этом хвост
этой НВП будет лексикографически наименьшим, а значение len
равно длине НВП для последовательности
x0, x1, …,
xi.
При обработке очередного элемента xi вставим его в
массив lis при помощи
бинарного поиска. Если xi больше значения lislen-1, то элемент xi увеличивает на
единицу длину НВП, поэтому устанавливаем lislen = xi и увеличиваем len на 1. Если lisk < xi £ lisk+1, то заменяем lisk+1 на xi. Эта операция
не увеличивает длину НВП, но может лексикографически уменьшить хвост НВП.
После обработки всех элементов массива х значение len содержит длину НВП.
Пример
Для заданной в
примере последовательности НВП может быть {3, 5, 6} или {3, 5, 28}. Длина НВП
равна 3.
Рассмотрим
следующий массив
Промоделируем на
нем работу алгоритма. В каждой новой строке приведем состояние массива после очередной
итерации.
Значение len = 5, следовательно длина
НВП равна 5. Ею, например, может быть следующая последовательность:
Реализация алгоритма
Входную
последовательность храним в массиве x. Объявим вспомогательный массив lis.
#define MAX 1001
int x[MAX], lis[MAX];
Основная часть программы. Читаем входную последовательность.
scanf("%d",&n);
for(i = 0; i < n; i++) scanf("%d",&x[i]);
Проводим n итераций
алгоритма.
for (len = i = 0; i < n; i++)
{
pos =
lower_bound(lis,lis+len,x[i]) - lis;
if (pos < len) lis[pos] = x[i]; else lis[len++] = x[i];
}
Выводим длину НВП.
printf("%d\n",len);
Реализация алгоритма – STL
vector
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> x, lis;
int i, n, len, pos;
int main(void)
{
scanf("%d", &n);
x.resize(n);
for (i = 0; i < n; i++)
scanf("%d", &x[i]);
for (i = 0; i < n; i++)
{
pos = lower_bound(lis.begin(), lis.end(), x[i]) - lis.begin();
if (pos < lis.size())
lis[pos] = x[i]; else lis.push_back(x[i]);
}
printf("%d\n", lis.size());
return 0;
}
Реализация алгоритма – O(n2)
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> x, lis;
int i, j, n, res;
int main(void)
{
scanf("%d", &n);
x.resize(n); lis.resize(n);
for (i = 0; i < n;
i++)
{
scanf("%d", &x[i]);
lis[i] = 1;
}
for (i = 0; i < n;
i++)
for (j = 0; j < i;
j++)
if (x[j] < x[i]) lis[i] =
max(lis[i], 1 + lis[j]);
res = *max_element(lis.begin(),
lis.end());
printf("%d\n", res);
return 0;
}
Java реализация
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Scanner con = new
Scanner(System.in);
int n = con.nextInt();
int x[] = new int[n];
for (int i = 0; i < n; i++)
x[i] = con.nextInt();
int lis[] = new int[n];
int len = 0;
for (int i = 0; i < n; i++)
{
int pos = Arrays.binarySearch(lis, 0, len, x[i]);
if(pos < 0) pos = - (pos + 1);
lis[pos] = x[i];
if(pos == len) len++;
}
System.out.println(len);
con.close();
}
}