OK, je vais d'abord décrire la solution la plus simple qui est O(N^2), où N est la taille de la collection. Il existe également une solution O(N log N), que je décrirai également. Regardez aquí pour cela à la section Algorithmes efficaces.
Je vais supposer que les indices du tableau sont de 0 à N - 1. Définissons donc DP[i]
est la longueur de la sous-séquence croissante la plus longue (LIS) qui se termine à l'élément avec l'indice i
. Pour calculer DP[i]
nous examinons tous les indices j < i
et vérifier à la fois si DP[j] + 1 > DP[i]
y array[j] < array[i]
(nous voulons qu'elle soit croissante). Si cela est vrai, nous pouvons mettre à jour l'optimum actuel de DP[i]
. Pour trouver l'optimum global pour le tableau, vous pouvez prendre la valeur maximale de DP[0...N - 1]
.
int maxLength = 1, bestEnd = 0;
DP[0] = 1;
prev[0] = -1;
for (int i = 1; i < N; i++)
{
DP[i] = 1;
prev[i] = -1;
for (int j = i - 1; j >= 0; j--)
if (DP[j] + 1 > DP[i] && array[j] < array[i])
{
DP[i] = DP[j] + 1;
prev[i] = j;
}
if (DP[i] > maxLength)
{
bestEnd = i;
maxLength = DP[i];
}
}
J'utilise le tableau prev
pour pouvoir ensuite trouver la séquence réelle et pas seulement sa longueur. Il suffit de remonter récursivement de bestEnd
dans une boucle en utilisant prev[bestEnd]
. Le site -1
valeur est un signe pour s'arrêter.
OK, passons maintenant au plus efficace O(N log N)
solution :
Soit S[pos]
est défini comme le plus petit entier qui termine une séquence croissante de longueur pos
. Maintenant, itérons à travers tous les entiers X
de l'ensemble d'entrée et faire ce qui suit :
-
Si X
> dernier élément dans S
puis ajouter X
à la fin de S
. Cela signifie essentiellement que nous avons trouvé un nouveau plus grand LIS
.
-
Sinon, trouvez le plus petit élément dans S
qui est >=
que X
et le changer en X
. Parce que S
est trié à tout moment, l'élément peut être trouvé en utilisant la recherche binaire dans log(N)
.
Temps d'exécution total - N
entiers et une recherche binaire pour chacun d'eux - N * log(N) = O(N log N)
Maintenant, prenons un exemple concret :
Collection d'entiers : 2 6 3 4 1 2 9 5 8
Des pas :
0. S = {} - Initialize S to the empty set
1. S = {2} - New largest LIS
2. S = {2, 6} - New largest LIS
3. S = {2, 3} - Changed 6 to 3
4. S = {2, 3, 4} - New largest LIS
5. S = {1, 3, 4} - Changed 2 to 1
6. S = {1, 2, 4} - Changed 3 to 2
7. S = {1, 2, 4, 9} - New largest LIS
8. S = {1, 2, 4, 5} - Changed 9 to 5
9. S = {1, 2, 4, 5, 8} - New largest LIS
La longueur du LIS est donc 5
(la taille de S).
Pour reconstruire le réel LIS
nous utiliserons à nouveau un tableau parent. Soit parent[i]
être le prédécesseur d'un élément avec l'indice i
dans le LIS
se terminant à l'élément avec l'indice i
.
Pour simplifier les choses, nous pouvons garder dans le tableau S
pas les entiers réels, mais leurs indices (positions) dans l'ensemble. Nous ne gardons pas {1, 2, 4, 5, 8}
mais gardez {4, 5, 3, 7, 8}
.
C'est-à-dire entrée [4] = 1 , input[5] = 2 , input[3] = 4 , input[7] = 5 , input[8] = 8 .
Si nous mettons à jour correctement le tableau parent, le LIS réel est :
input[S[lastElementOfS]],
input[parent[S[lastElementOfS]]],
input[parent[parent[S[lastElementOfS]]]],
........................................
Passons maintenant à l'essentiel : comment mettre à jour le tableau parent ? Il y a deux possibilités :
-
Si X
> dernier élément dans S
entonces parent[indexX] = indexLastElement
. Cela signifie que le parent de l'élément le plus récent est le dernier élément. Nous ajoutons simplement X
à la fin de S
.
-
Sinon, trouvez l'indice du plus petit élément dans S
qui est >=
que X
et le changer en X
. Ici parent[indexX] = S[index - 1]
.
12 votes
En parlant de la solution DP, j'ai trouvé surprenant que personne n'ait mentionné le fait que LIS peut être réduit à LCS .
0 votes
Très bien expliqué LIS