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 > rdal momento che il prodotto è commutativo.
A causa delle restrizioni abs(s-r) > kquesto implica che s >= k+1. Ora, sciascuno degli indici potrebbe soddisfare questa condizione, quindi ripetiamo questi indici. Questa è l'iterazione inel codice mostrato, ma viene spostata k+1per comodità (non importa davvero). Per ogni iterazione dobbiamo trovare il prodotto ottimale che coinvolge i+k+1come indice più grande e confrontarlo con la migliore ipotesi precedente.
I possibili indici da abbinare i+k+1sono tutti gli indici più piccoli o uguali a icausa della distanza richiesta. Dovremmo iterare anche su tutti questi, ma ciò non è necessario perché il minimo di a[i+k+1]*a[j]over ja 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_maxe back_minnell'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.