En supposant qu'il y ait au moins une paire d'éléments satisfaisant aux conditions et qu'aucune multiplication de deux éléments ne déborde, cela peut être fait dans le pire et le meilleur des cas dans le Theta(n-k)
temps et l' Theta(1)
espace, avec quelque chose comme ceci:
auto back_max = a[0];
auto back_min = a[0];
auto best = a[0]*a[k+1];
for(std::size_t i=1; i<n-(k+1); ++i) {
back_max = std::max(back_max, a[i]);
back_min = std::min(back_min, a[i]);
best = std::min(best, std::min(a[i+k+1]*back_max, a[i+k+1]*back_min));
}
return best;
C'est optimal en termes de complexité asymptotique dans le pire des cas, à la fois dans le temps et dans l'espace, car le produit optimal peut être a[0]
avec au moins l'un des n-(k+1)
éléments à distance k+1
, donc au moins les n-(k+1)
entiers doivent être lus par tout algorithme résolvant le problème.
L'idée derrière l'algorithme est la suivante:
Le produit optimal utilise deux éléments de a
, supposons que ce soient a[r]
et a[s]
. Sans perte de généralité, nous pouvons supposer que s > r
puisque le produit est commutatif.
En raison de la restriction, abs(s-r) > k
cela implique que s >= k+1
. Maintenant, s
chacun des indices pourrait satisfaire à cette condition, donc nous itérons sur ces indices. C'est l'itération i
dans le code affiché, mais elle est décalée k+1
pour plus de commodité (peu importe). Pour chaque itération, nous devons trouver le produit optimal impliquant i+k+1
le plus grand indice et le comparer avec la meilleure estimation précédente.
Les indices possibles à coupler i+k+1
sont tous des indices plus petits ou égaux en i
raison de la distance requise. Nous aurions besoin d'itérer sur tous ces éléments également, mais cela n'est pas nécessaire car le minimum de a[i+k+1]*a[j]
sur j
à fixe i
est égal à en min(a[i+k+1]*max(a[j]), a[i+k+1]*min(a[j]))
raison de la monotonie du produit (en prenant le minimum en ce qui concerne à la fois le minimum et le maximum sur les a[j]
comptes pour les deux possibles signes a[i+k+1]
ou équivalents des deux directions possibles de la monotonie.)
Puisque l'ensemble de a[j]
valeurs sur lesquelles nous optimisons ici est juste {a[0], ..., a[i]}
, qui croît simplement d'un élément ( a[i]
) à chaque itération de i
, nous pouvons simplement garder une trace de max(a[j])
et min(a[j])
avec des variables uniques en les mettant à jour si elles a[i]
sont plus grandes ou plus petites que les valeurs optimales précédentes. Cela se fait avec back_max
et back_min
dans l'exemple de code.
La première étape de l'itération ( i=0
) est ignorée dans la boucle et effectuée à la place comme initialisation des variables.
std::vector
? @Scheff - le tri détruirait les relations "de distance" d'origine.