Je veux prouver ou infirmer l'existence d'un algorithme qui, étant donné un tableau d'entiers, trouve trois indices i , j et k tels que i < j < k et A [ i ] < A [ j ] < A [ k ] (ou constate qu'il n'y a pas un tel triple) en temps linéaire.
Ce n'est pas une question de devoirs; Je l'ai vu sur un forum de programmation conçu comme «essayez d'implémenter un tel algorithme». Je soupçonne que c'est impossible après diverses expériences. Mon intuition me le dit, mais cela ne compte vraiment pour rien.
Je voudrais le prouver formellement. Comment faites-vous? J'aimerais idéalement voir une preuve présentée étape par étape, puis si vous êtes si enclin, une explication sur la façon de prouver / réfuter des questions simples comme celle-ci en général. Si cela peut vous aider, quelques exemples:
[1,5,2,0,3] → (1,2,3)
[5,6,1,2,3] → (1,2,3)
[1,5,2,3] → (1,2,3)
[5,6,1,2,7] → (1,2,7)
[5,6,1,2,7,8] → (1,2,7)
[1,2,999,3] → (1,2,999)
[999,1,2,3] → (1,2,3)
[11,12,8,9,5,6,3,4,1,2,3] → (1,2,3)
[1,5,2,0,-5,-2,-1] → (-5,-2,-1)
J'ai supposé que l'on pouvait itérer sur , et chaque fois qu'il y a un i < j (notre j actuel , c'est-à-dire), nous faisons un nouveau triple et le poussons sur un tableau. Nous continuons à avancer et à comparer chaque triple jusqu'à ce que l'un de nos triplets soit complet. Il est donc comme , ! Mais je pense que c'est plus complexe que le simple O ( n ) car le nombre de triplets sur notre triple tableau correspondrait dans le pire des cas à la taille de la liste d'entrée.[1,5,2,0,-5,-2,-1] → 1..2.. -5.. -2.. -1
[1,5,2,0,-5,-2,3,-1] → 1..2.. -5.. -2.. 3
la source
Réponses:
Il s'agit de la variation du problème de sous- séquence croissant le plus long ; c'est la solution présentée sur Wikipédia en utilisant deux tableaux auxiliaires et P :M P
Cet algorithme s'exécute dans le pire des cas . Votre problème est un cas spécial qui vous permet de retourner lorsque L = 3 qui pousse le runtime à O ( n ) car la recherche binaire ne s'exécute que sur des tableaux de longueur au plus deux, ce qui est donc dans le temps O ( 1 ) par opposition à Θ ( log n ) dans le cas général.Θ ( n logn ) L = 3 O ( n ) O ( 1 ) Θ ( journaln )
Considérez le pseudo-code modifié:
la source
Une note sur la méthodologie
J'ai réfléchi un peu à ce problème et suis parvenu à une solution. Quand j'ai lu la réponse de Saeed Amiri , j'ai réalisé que ce que j'ai trouvé était une version spécialisée de l'algorithme de recherche de sous-séquence le plus long standard pour une séquence de longueur 3. Je poste la façon dont j'ai trouvé la solution, parce que je pense qu'elle est un exemple intéressant de résolution de problèmes.
La version à deux éléments
Ce cas est très simple; nous essaierons de le généraliser. Cela montre que le problème tel qu'il est énoncé n'est pas résoluble: les indices demandés n'existent pas toujours. Nous demanderons donc plutôt que l'algorithme renvoie des indices valides, s'ils existent, ou affirme correctement qu'aucun indice de ce type n'existe.
Venir avec l'algorithme
Nous venons de voir que les indices demandés n'existent pas toujours. Notre stratégie sera d'étudier lorsque les indices n'existent pas. Nous le ferons en supposant que nous essayons de trouver les indices et de voir comment notre recherche pourrait mal tourner. Ensuite, les cas où la recherche ne se passe pas mal fourniront un algorithme pour trouver les indices.
Énoncé de l'algorithme
Donné en syntaxe Python, mais attention, je ne l'ai pas testé.
Croquis de preuve
index1
est l'indice du minimum de la partie du tableau qui a déjà été parcourue (s'il se produit plusieurs fois, on retient la première occurrence), ouNone
avant de traiter le premier élément.index2
stocke les indices de la sous-séquence croissante de longueur 2 dans la partie déjà traversée du tableau qui a l'élément le plus grand le plus bas, ouNone
si une telle séquence n'existe pas.Lors des
return (index2[0], index2[1], i)
exécutions, nous avonsvalue2[0] < value[1]
(c'est un invariant devalue2
) etvalue[1] < A[i]
(évident d'après le contexte). Si la boucle se termine sans invoquer le retour anticipévalue1 == None
, dans ce cas, il n'y a pas de sous-séquence croissante de longueur 2 sans parler de 3, ouvalue1
contient la sous-séquence croissante de longueur 2 qui a l'élément le plus grand le plus bas. Dans ce dernier cas, nous avons en outre l'invariant qu'aucune sous-séquence croissante de longueur 3 ne se termine plus tôt quevalue1
; par conséquent, le dernier élément d'une telle sous-séquence, ajouté àvalue2
, formerait une sous-séquence croissante de longueur 3: comme nous avons également l'invariant quivalue2
ne fait pas partie d'une sous-séquence croissante de longueur 3 contenue dans la partie déjà traversée du tableau, il est pas une telle sous-séquence dans l'ensemble du tableau.Prouver les invariants susmentionnés est laissé comme un exercice pour le lecteur.
Complexité
Preuve formelle
Laissé en exercice au lecteur.
la source
Tout d'abord, parcourez le tableau de gauche à droite en conservant une pile et un tableau auxiliaire qui vous indique pour chaque élément, l'indice d'un élément supérieur à lui et à droite de celui-ci.
Chaque fois que vous considérez un nouvel élément dans le tableau, si cet élément est supérieur à l'élément supérieur de la pile, vous le supprimez de la pile et définissez l'élément de tableau aux correspondant au sommet pour avoir l'index du nouvel élément sous considération.
Continuez à extraire des éléments de la pile et à définir l'index correspondant, tandis que l'élément en cours est supérieur. Une fois que le sommet a un élément qui n'est pas moindre (ou devient vide), poussez l'élément actuel sur la pile et passez à l'élément suivant du tableau, en répétant l'étape ci-dessus.
Faites un autre passage (et un autre tableau auxiliaire), mais en allant de droite à gauche.
Le pseudo-code de la première passe peut ressembler à ceci:
la source