Je pense que l'algorithme suivant s'exécute en O(n) temps et produit une solution optimale. C'est un peu délicat, donc je vais diviser la logique en deux cas, un dans lequel nous considérons le cas où il n'y a pas de valeurs dupliquées dans le tableau, et un dans lequel nous avons considéré le cas où les duplications sont autorisées.
La structure de données clé que nous utiliserons est le fichier Arbre cartésien Il s'agit d'un max-heap construit à partir d'une gamme de données et dont la propriété est qu'une marche en ordre des nœuds de l'arbre produit les valeurs de la séquence dans l'ordre dans lequel elles apparaissent. Le détail critique est qu'il est possible de construire un arbre cartésien pour une séquence d'éléments en O(n) temps.
À titre d'exemple, étant donné la séquence 4 1 0 3 2, nous obtiendrions cet arbre cartésien :
4
\
3
/ \
1 2
\
0
Remarquez que la marche en ordre donne effectivement 4 1 0 3 2.
Je prétends maintenant que les extrémités de l'intervalle que nous recherchons doivent être une paire parent/enfant dans l'arbre cartésien (c'est-à-dire que le premier nœud est un parent du second nœud ou vice-versa). Notez que nous sommes no en recherchant un nœud et n'importe quel ancêtre, mais spécifiquement une paire parent/enfant. Pour prouver cela, je prouve les deux affirmations suivantes :
Revendication 1 : Toute paire parent/enfant dans l'arbre cartésien définit une plage de valeurs dans la séquence originale qui n'a pas de valeurs intermédiaires supérieures aux points d'extrémité.
Revendication 2 : Toute plage de valeurs dans la séquence qui n'a pas de valeurs intermédiaires supérieures à ses points d'extrémité doit avoir ces points d'extrémité comme paire parent/enfant dans l'arbre cartésien.
Pris ensemble, ces éléments prouvent que l'intervalle que nous recherchons doit être une paire parent/enfant dans l'arbre cartésien. Cela nous donne alors un algorithme facile en temps linéaire pour résoudre le problème lorsque toutes les valeurs sont distinctes. Tout d'abord, en temps O(n), on construit un arbre cartésien pour l'intervalle. Ensuite, on explore récursivement l'arbre et, pour chaque paire parent/enfant, on trouve la distance entre ces paires, en prenant la plus grande plage trouvée. Cette deuxième étape s'exécute également en O(n), puisqu'un arbre cartésien est un arbre binaire et que le nombre d'arêtes est donc O(n).
Preuve de la première revendication : Une paire parent/enfant doit ressembler soit à
u
\
v
/ \
A B
ou
u
/
v
/ \
A B
Rappelons qu'un arbre cartésien stocke ses éléments de manière à ce qu'une traversée en ordre des éléments de l'arbre donne les éléments du tableau utilisé pour produire l'arbre dans l'ordre dans lequel ils apparaissent dans le tableau. Cela signifie que dans le cas (1), nous regardons une plage d'éléments commençant par u, contenant tout A, et se terminant par b. De même, dans le cas (2), la plage commence par v, puis contient tout B, et se termine par u. Nous prouvons par contradiction l'affirmation selon laquelle u et v n'ont pas de valeurs intermédiaires plus grandes que u ou v. Supposons que ce soit le cas et que la valeur w soit plus grande que u ou v. Par la définition d'un arbre cartésien, si w est entre u et v dans la séquence originale, alors dans le cas (1) il doit être dans le sous-arbre A et dans le cas (2) il doit être dans le sous-arbre B. Mais un arbre cartésien est un max-heap, et donc dans le cas (1) à la fois u et v sont plus grands que tout dans A, et dans le cas (2) à la fois u et v sont plus grands que tout dans B, une contradiction. Ainsi, l'intervalle de valeurs entre toute paire parent/enfant ne doit pas être plus grand que le parent ou l'enfant.
Preuve de la revendication 2 : Par contrapositif ; nous montrons que s'il existe une sous-séquence du tableau original commençant par u et se terminant par v qui contient un élément plus grand w que u ou v, alors u et v ne peuvent pas être une paire parent/enfant ou enfant/parent dans l'arbre cartésien. La preuve est virtuellement identique à la précédente - si u et v étaient une paire parent/enfant, alors dans le cas (1) ci-dessus, w devrait être dans A et dans le cas (2), w devrait être dans B, dans les deux cas violant le fait qu'un arbre cartésien est un tas maximum.
Les preuves ci-dessus nous montrent que si toutes les valeurs sont distinctes, nous pouvons résoudre ce problème en temps linéaire en construisant simplement un arbre cartésien et en effectuant une simple marche dans l'arbre. Mais que se passe-t-il si les éléments peuvent être dupliqués, comme dans l'énoncé original du problème ? Dans ce cas, nous pouvons utiliser une structure d'arbre cartésien modifiée. Nous autoriserons les nœuds à être combinés en un "méta-nœud" de plusieurs valeurs différentes de l'arbre cartésien qui partagent la même valeur. Par exemple, la séquence 2 7 1 7 8 0 3 8 2 ressemblerait à ceci :
[8 ------- 8]
/ \ \
/ 3 2
/ /
/ 0
/
[7 -- 7]
/ \
2 1
Ici, la racine est un métanode composé de deux nœuds de valeur 8, et le premier métanode 8 est composé de deux métanodes 7.
À des fins de notation, le nœud "le plus à gauche" d'un métanode est le nœud le plus à gauche du métanode et le nœud "le plus à droite" d'un métanode est le nœud le plus à droite du métanode.
Dans cet arbre cartésien modifié, nous pouvons définir une marche en ordre des nœuds comme une marche qui visite tous les nœuds d'un méta-nœud dans l'ordre de gauche à droite, en effectuant une marche en ordre de chacun des nœuds qu'il contient. Nous imposons ensuite que l'arbre cartésien modifié a strict max-heap (chaque nœud doit être strictement plus grand que n'importe lequel de ses enfants) et qu'une marche en ordre de l'arbre donne les valeurs dans le même ordre que celui dans lequel elles apparaissent dans la séquence originale.
Remarquez que cette construction généralisée contient notre solution originale comme un cas spécial - si toutes les valeurs sont distinctes, rien n'est différent dans cette structure arborescente. Je vais également affirmer sans preuve qu'il est possible de construire une de ces structures en O(n) par une modification directe de l'algorithme standard des arbres cartésiens.
Dans cette structure arborescente modifiée, une plage de valeurs sans valeurs intermédiaires au moins aussi grande que les points d'extrémité correspond à l'un ou l'autre :
- Un parent et le nœud le plus à droite de son enfant gauche.
- Un parent et le nœud le plus à gauche de son enfant de droite.
- Deux nœuds adjacents dans le même métanode.
La preuve des deux premières revendications est une modification assez simple de la preuve du cas précédent. La différence est qu'au lieu que la preuve de contradiction dise que cela violerait la propriété max-heap, on dirait plutôt que cela viole la propriété max-heap forte. Vous diriez également que toutes les valeurs égales au milieu de la plage devraient se manifester comme des nœuds qui empêcheraient les extrémités de la plage d'être les nœuds les plus à gauche ou les plus à droite dans un métanode. La preuve de la troisième affirmation est (en gros) que tous les nœuds entre les deux nœuds doivent être strictement plus petits que les extrémités, et s'il y avait une valeur égale au milieu, alors les deux nœuds ne seraient pas des métanœuds adjacents.
Compte tenu de cette observation, nous pouvons résoudre le problème original en temps O(n) comme suit. Tout d'abord, on construit un arbre cartésien généralisé à partir de la plage d'entrée. Ensuite, parcourez l'arbre et examinez toutes les paires d'éléments indiquées qui pourraient constituer la plage, en choisissant la plus grande que vous trouvez. Puisque pour chaque nœud, seul un nombre constant d'autres nœuds doit être vérifié (son parent, ses frères et sœurs de gauche et de droite, et ses enfants donnent au maximum cinq nœuds à vérifier), ceci peut être fait en O(n) temps pour un temps d'exécution net de O(n).
Ouf ! C'était un problème génial. Je ne sais pas si c'est une solution idéale, mais cela prouve au moins qu'il est possible de le faire en O(n) temps. Si quelqu'un trouve une meilleure solution, j'aimerais bien la voir.