Grade 11 · Dynamic programmingCitește în română
Longest strictly increasing subsequence
Original: Subșirul strict crescător de lungime maximă
The idea
From a sequence of n numbers we choose a strictly increasing subsequence (elements in their order in the sequence, not necessarily adjacent) that is as long as possible. L[i] is the length of the longest increasing subsequence starting with a[i]. We compute from right to left: L[i] = 1 + max{ L[j] : j > i, a[j] > a[i] } (or 1 if there is no such j). The answer is the largest L[i]. To rebuild it we start from that i and always look for the first j after it with a[j] > a[i] and L[j] = L[i] - 1. The length and a longest subsequence are printed.
Original description (Romanian)
Dintr-un șir de n numere alegem un subșir (elemente în ordinea din șir, nu neapărat alăturate) strict crescător și cât mai lung. L[i] este lungimea celui mai lung subșir crescător care începe cu a[i]. Calculăm de la dreapta la stânga: L[i] = 1 + max{ L[j] : j > i, a[j] > a[i] } (sau 1 dacă nu există un astfel de j). Răspunsul este cel mai mare L[i]. Pentru reconstituire pornim de la acel i și căutăm mereu primul j de după el cu a[j] > a[i] și L[j] = L[i] - 1. Se afișează lungimea și un subșir maximal.
- Complexity
- O(n²) timp, O(n) memorie
- Grade
- Grade 11 (Clasa a XI-a)
- Chapter
- Dynamic programming
Examples
Input
8 5 1 7 3 4 9 2 8
Expected output
4 1 3 4 9
The code
Comments are in Romanian, as in the original collection. Edit freely: you can reset at any time.
/*
* Titlu: Subșirul strict crescător de lungime maximă
* Clasa: 11
* Capitol: Programare dinamică
* Descriere: Dintr-un șir de n numere alegem un subșir (elemente în ordinea din șir, nu
* neapărat alăturate) strict crescător și cât mai lung. L[i] este lungimea
* celui mai lung subșir crescător care începe cu a[i]. Calculăm de la dreapta
* la stânga: L[i] = 1 + max{ L[j] : j > i, a[j] > a[i] } (sau 1 dacă nu există
* un astfel de j). Răspunsul este cel mai mare L[i]. Pentru reconstituire pornim
* de la acel i și căutăm mereu primul j de după el cu a[j] > a[i] și
* L[j] = L[i] - 1. Se afișează lungimea și un subșir maximal.
* Complexitate: O(n²) timp, O(n) memorie
*
* Exemplu
* Intrare:
* 8
* 5 1 7 3 4 9 2 8
* Ieșire:
* 4
* 1 3 4 9
*/
#include <iostream>
using namespace std;
int a[1005], L[1005];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = n; i >= 1; i--)
{
L[i] = 1;
for (int j = i + 1; j <= n; j++)
{
if (a[j] > a[i] && L[j] + 1 > L[i])
{
L[i] = L[j] + 1;
}
}
}
int start = 1;
for (int i = 2; i <= n; i++)
{
if (L[i] > L[start])
{
start = i;
}
}
cout << L[start] << '\n';
int i = start;
cout << a[i] << ' ';
for (int j = i + 1; j <= n; j++)
{
if (a[j] > a[i] && L[j] == L[i] - 1)
{
cout << a[j] << ' ';
i = j;
}
}
cout << '\n';
return 0;
}
Runs on a real g++ (C++17, -O2) through Compiler Explorer. Keep runs short; there's a time limit.