Supponendo che vi sia almeno una coppia di elementi che soddisfi le condizioni e che non vi sia una moltiplicazione di due elementi in esso trabocca, ciò può essere fatto nel Theta(n-k)
tempo e Theta(1)
nello spazio peggiori e nel migliore dei casi, con qualcosa del genere:
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;
Questo è ottimale in termini di complessità asintotica nel caso peggiore sia per il tempo che per lo spazio perché il prodotto ottimale può essere almeno a[0]
con uno qualsiasi degli n-(k+1)
elementi in lontananza k+1
, quindi almeno gli n-(k+1)
interi devono essere letti da qualsiasi algoritmo che risolva il problema.
L'idea alla base dell'algoritmo è la seguente:
Il prodotto ottimale utilizza due elementi di a
, supponiamo che siano a[r]
e a[s]
. Senza perdita di generalità possiamo supporre che s > r
dal momento che il prodotto è commutativo.
A causa delle restrizioni abs(s-r) > k
questo implica che s >= k+1
. Ora, s
ciascuno degli indici potrebbe soddisfare questa condizione, quindi ripetiamo questi indici. Questa è l'iterazione i
nel codice mostrato, ma viene spostata k+1
per comodità (non importa davvero). Per ogni iterazione dobbiamo trovare il prodotto ottimale che coinvolge i+k+1
come indice più grande e confrontarlo con la migliore ipotesi precedente.
I possibili indici da abbinare i+k+1
sono tutti gli indici più piccoli o uguali a i
causa della distanza richiesta. Dovremmo iterare anche su tutti questi, ma ciò non è necessario perché il minimo di a[i+k+1]*a[j]
over j
a fixed i
è uguale a min(a[i+k+1]*max(a[j]), a[i+k+1]*min(a[j]))
causa della monotonicità del prodotto (prendendo il minimo rispetto a entrambi i a[j]
conti di minimo e massimo per i due possibili segni a[i+k+1]
o equivalenti delle due possibili direzioni della monotonicità.)
Poiché l'insieme di a[j]
valori su cui ottimizziamo qui è giusto {a[0], ..., a[i]}
, che semplicemente aumenta di un elemento ( a[i]
) in ogni iterazione di i
, possiamo semplicemente tenere traccia di max(a[j])
e min(a[j])
con singole variabili aggiornandole se a[i]
è maggiore o minore dei precedenti valori ottimali. Questo viene fatto con back_max
e back_min
nell'esempio di codice.
Il primo passaggio dell'iterazione ( i=0
) viene ignorato nel ciclo e invece eseguito come inizializzazione delle variabili.
std::vector
? @Scheff - l'ordinamento distruggerebbe le relazioni "a distanza" originali.