Numéro de l'accroissement de sous-séquences dans la séquence donnée?
Vous avez entendu parler du problème bien connu de trouver le plus longue sous-suite croissante. L'algorithme optimal a O(n*log(n))
complexité.
Je pensais au problème de trouver tous croissante de sous-séquences dans la séquence donnée. J'ai trouvé la solution pour un problème où nous avons besoin de trouver un nombre croissant de sous-séquences de longueur k, qui a O(n*k*log(n))
complexité (où n est une longueur de la séquence).
Bien sûr, cet algorithme peut être utilisé pour mon problème, mais ensuite, la solution a O(n*k*log(n)*n) = O(n^2*k*log(n))
de complexité, je suppose. Je pense qu'il doit y avoir un mieux (je veux dire - plus rapide) de la solution, mais je ne sais pas comme encore.
Si vous savez comment résoudre le problème de la recherche de tous croissante de sous-séquences dans la séquence donnée dans optimal de l'heure/de la complexité (dans ce cas, optimal = mieux que O(n^2*k*log(n)))
, s'il vous plaît laissez-moi savoir à ce sujet.
À la fin: ce problème n'est pas des devoirs à faire. Il y était mentionné sur mon exposé d'un problème de la plus longue sous-suite croissante et j'ai commencé à penser à l'idée générale de tous croissante de sous-séquences dans la séquence donnée.
OriginalL'auteur exTyn | 2011-01-08
Vous devez vous connecter pour publier un commentaire.
Je ne sais pas si c'est optimal - probablement pas, mais voici une DP solution dans
O(n^2)
.Laisser
dp[i] = number of increasing subsequences with i as the last element
Puis c'est juste une question de sommation de toutes les entrées dans
dp
Sebastian - dirait qu'il travaille pour facilement vérifié entrée! :). Je pensais à une formule basée sur le nombre d'éléments égaux et des inversions dans le tableau donné, mais je n'ai pas obtenu loin. Qui pourrait être en mesure de l'obtenir vers le bas pour
O(n log n)
. Peut-être plus avancée structures de données peuvent descendre à cette complexité.Solution élégante, merci!
OriginalL'auteur IVlad
Vous pouvez calculer le nombre croissant de sous-séquences en O(n log n) comme suit.
Rappel de l'algorithme pour la longueur de la plus longue sous-suite croissante:
Pour chaque élément, calculer le prédécesseur élément parmi les éléments précédents, et ajouter à cela la longueur.
Cet algorithme s'exécute naïvement en O(n^2), et s'exécute en O(n log n) (ou encore mieux, dans le cas des nombres entiers), si vous calculez le prédécesseur à l'aide d'une structure de données comme un équilibre binaire un arbre de recherche (BST) (ou quelque chose de plus avancé comme un van Emde Boas arbre pour les entiers).
De modifier cet algorithme pour le calcul du nombre de séquences, de les stocker dans la BST dans chaque nœud, le nombre de séquences se terminant à cet élément. Lors du traitement de l'élément suivant dans la liste, il vous suffit de rechercher le prédécesseur, compter le nombre de séquences se terminant à un élément qui est inférieur à l'élément en cours de traitement (en O(log n) le temps), et stocker le résultat dans la BST avec l'élément courant. Enfin, vous avez la somme des résultats pour chaque élément de l'arborescence pour obtenir le résultat.
Comme une mise en garde, note que le nombre croissant de séquences pourraient être très grande, de sorte que l'arithmétique ne prend plus de O(1) fois par opération. Cela doit être pris en considération.
Psuedocode:
O(n log n)
algorithme pour le LIS problème que vous décrivez, on peut supprimer la boucle interne de l'algorithme classique avec une requête dans un BST pour une valeur maximale. Si vous somme, ces comme vous le dites, pour chaque nœud / élément que vous allez seulement la somme du nombre de plus longue croissante de sous-séquences se terminant à cet élément. Par exemple, pour1 2 3
, vous ne comptez1, 1 2, 1 2 3
. Si ce n'est de toute façon pas le cas, vous pouvez poster une mise en œuvre ou au moins certains de pseudo s'il vous plaît?2=>2},
3: {1=>1, 2=>2, 3=>4}
. Par exemple, lors de la rencontre d'3, il y a deux touches d'entrée de moins de (1 et 2), et la valeur de 3 est les valeurs de ces touches, plus un (c 1->3, 1->2->3, 2->3, 3). Pour nous, pour le faire efficacement, nous tenons également à conserver à chaque nœud de la somme des valeurs dans le sous-arbre.Aussi longtemps que vous incluez dans le décompte pour chaque nœud, le singleton de la séquence, composé de l'élément lui-même, et la somme sur tous les éléments à la fin, il va fonctionner. L'invariant que nous utilisons est que chaque élément stocke le nombre de toutes les sous-séquences, pas nécessairement maximale, qui se terminent au niveau de ce nœud, qui est à seulement 1 + le nombre de séquences qui se terminent dans un plus petit nombre. Le second opérande de cette somme est calculée en utilisant augmentée arbres binaires de faire la somme des auxiliaires champs de la BST à partir d'éléments qui sont plus petits que l'élément courant. Je vais poster quelques pseudocode peu de temps.
savez-vous comment modifier cet algorithme pour obtenir uniquement le numéro de la plus longue augmentation de séquences?
Oui, je pense que cela devrait être possible si, pour chaque élément que vous stocker le nombre des plus longues séquences se terminant en. Pour calculer cette valeur pour l'élément i+1, compte tenu des valeurs de 0 à i, vous devez binaire de recherche pour trouver la longueur de la plus longue séquence se terminant dans l'élément i+1, puis effectuer une autre recherche dans un augmentée BST qui stocke les éléments de mettre fin à l'augmentation des séquences de longueur, moins de 1 (le BST nœuds sont augmenté avec le nombre croissant de séquences de longueur, et nous utilisons l'augmentation de faciliter le calcul du préfixe somme en O(lg n) le temps). Espérons que cela a du sens.
OriginalL'auteur jonderry
Je suppose sans perte de généralité de l'entrée[0..(n-1)] est constitué de tous les nombres entiers dans {0, 1, ..., n-1}.
Laisser DP[i] = nombre croissant de sous-séquences se terminant en[i].
Nous avons la récurrence:
Pour calculer DP[i], nous avons seulement besoin de calculer DP[j] pour tout j où A[j] < A[i]. Par conséquent, nous pouvons calculer la DP tableau dans l'ordre croissant des valeurs de A. Ce qui laisse DP[k] = 0 pour tout k où A[k] > A[i].
Le problème revient à calculer la somme DP[0] pour DP[i-1]. En supposant que nous avons déjà calculé DP[0] pour DP[i-1], on peut calculer DP[i] en O(log n) à l'aide d'un Fenwick arbre.
La réponse finale est ensuite DP[0] + DP[1] + ... DP[n-1]. L'algorithme s'exécute en temps O(n log n).
Quid du cas où une valeur apparaît plus d'une fois? Avez-vous pensé à elle @nhahtdh ?
Lorsque vous triez les chiffres (pour calculer la somme dans l'ordre croissant des valeurs de A), si les 2 nombres ont la même valeur, à les trier par index dans l'ordre décroissant.
Pouvez-vous nous en dire un peu plus en détail, sur la façon d'utiliser Fenwik arbre pour calculer
DP[i]
donné,DP[0]
,DP[1]
....DP[n-1]
.Représenter DP comme une fréquence de tableau dans Fenwick arbre. Ensuite, vous pouvez calculer gamme somme en O(log n), en faisant un préfixe somme.
OriginalL'auteur bloops
C'est un O(nklogn) solution où n est la longueur du tableau d'entrée et k est la taille de l'augmentation de la sous-séquences. Il est basé sur le solution mentionnée dans la question.
vector<int> values
, un n longueur de la matrice, est la matrice pour la recherche croissante de sous-séquences.mapIndex
contient maintenant un classement de tous les numéros devalues
.Après avoir placé tous les n éléments de
values
dans tous les k dimensions debinaryIndexTree
. Levalue
s recueillies dansresult
représentent le nombre total de l'augmentation de la sous-séquences de longueur k.L'index binaire des fonctions d'arbre utilisé pour obtenir ce résultat sont:
L'index binaire arbre est évidemment O(nklogn), mais c'est la capacité de manière séquentielle remplir qui crée la possibilité de l'utiliser pour une solution.
mapIndex
crée un classement pour chaque nombre dansvalues
, de telle sorte que le plus petit nombre dansvalues
a un rang de 1. (Par exemple sivalues
est "2, 3, 4, 3, 4, 1" puismapIndex
contiendra: "{1, 1}, {2, 2}, {3, 3}, {4, 5}". Notez que "4" a un rang de "5" car il y a 2 "3"s dansvalues
binaryIndexTree
a k différents arbres, niveau x représentent le nombre total d'augmenter les sous-chaînes de caractères qui peuvent être formés de longueur x. N'importe quel nombre dansvalues
pouvez créer une sous-chaîne de longueur 1, de sorte que chaque élément de l'incrémenter de rang et tous les rangs au-dessus de 1.À des niveaux supérieurs, une augmentation de la sous-chaîne dépend il y a déjà une sous-chaîne de longueur plus courte et de rang inférieur.
Parce que les éléments sont insérés dans l'index binaire de l'arbre en fonction de leur ordre dans
values
, l'ordre d'apparition dansvalues
est préservée, de sorte que si un élément a été inséré dansbinaryIndexTree
c'est parce qu'elle a précédé l'élément en cours dansvalues
.Une excellente description de la façon dont binaire arbre d'index est disponible ici: http://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/
Vous pouvez trouver une version exécutable du code ici: http://ideone.com/GdF0me
OriginalL'auteur Jonathan Mee
Prenons un exemple -
Prendre un tableau {7, 4, 6, 8}
Maintenant, si vous considérez chaque élément comme une sous-suite, puis le nombre croissant de sous-suite qui peut être formé sont -
{7} {4} {6} {4,6} {8} {7,8} {4,8} {6,8} {4,6,8}
Un total de 9 sous-suite croissante peut être formé pour ce tableau.
Donc la réponse est 9.
Le code est comme suit -
La complexité du code est O(N log N).
OriginalL'auteur Rito
Version de Java comme un exemple:
OriginalL'auteur Ivan Voroshilin