Qual è la differenza tra memoization e programmazione dinamica? Penso che la programmazione dinamica sia un sottoinsieme della memoizzazione. È giusto?
Qual è la differenza tra memoization e programmazione dinamica? Penso che la programmazione dinamica sia un sottoinsieme della memoizzazione. È giusto?
Risposte:
Articolo pertinente su Programming.Guide: programmazione dinamica vs memoization vs tabulazione
Qual è la differenza tra memoization e programmazione dinamica?
Memoization è un termine che descrive una tecnica di ottimizzazione in cui si memorizzano nella cache i risultati precedentemente calcolati e si restituisce il risultato memorizzato nella cache quando è necessario nuovamente lo stesso calcolo.
La programmazione dinamica è una tecnica per risolvere i problemi di natura ricorsiva, in modo iterativo ed è applicabile quando i calcoli dei sottoproblemi si sovrappongono.
La programmazione dinamica viene in genere implementata mediante tabulazione, ma può anche essere implementata mediante la memoizzazione. Come puoi vedere, nessuno dei due è un "sottoinsieme" dell'altro.
Una ragionevole domanda di follow-up è: qual è la differenza tra tabulazione (la tipica tecnica di programmazione dinamica) e memoizzazione?
Quando si risolve un problema di programmazione dinamica utilizzando la tabulazione, si risolve il problema "dal basso verso l'alto ", vale a dire risolvendo innanzitutto tutti i problemi secondari correlati, in genere riempiendo una tabella n- dimensionale. Sulla base dei risultati nella tabella, viene quindi calcolata la soluzione al problema "principale" / originale.
Se si utilizza la memoization per risolvere il problema, farlo mantenendo una mappa di problemi secondari già risolti. Lo fai " top down ", nel senso che risolvi prima il problema "top" (che in genere ricade verso il basso per risolvere i problemi secondari).
Una buona diapositiva da qui (il link è ora morto, la diapositiva è comunque buona):
- Se tutti i sottoproblemi devono essere risolti almeno una volta, un algoritmo di programmazione dinamica bottom-up di solito supera un algoritmo memoized top-down di un fattore costante
- Nessun sovraccarico per la ricorsione e meno sovraccarico per il mantenimento della tabella
- Vi sono alcuni problemi per i quali è possibile sfruttare il modello regolare di accesso alle tabelle nell'algoritmo di programmazione dinamica per ridurre ulteriormente i requisiti di tempo o spazio
- Se alcuni sottoproblemi nello spazio dei sottoproblemi non devono essere risolti affatto, la soluzione memorizzata presenta il vantaggio di risolvere solo quei sottoproblemi che sono sicuramente richiesti
Risorse addizionali:
La programmazione dinamica è un paradigma algoritmico che risolve un dato problema complesso suddividendolo in sottoproblemi e memorizza i risultati dei sottoproblemi per evitare di calcolare nuovamente gli stessi risultati.
http://www.geeksforgeeks.org/dynamic-programming-set-1/
La memorizzazione è un metodo semplice per tenere traccia delle soluzioni precedentemente risolte (spesso implementate come coppia di valori chiave hash, al contrario della tabulazione che spesso si basa su array) in modo che non vengano ricalcolate quando vengono incontrate di nuovo. Può essere utilizzato in entrambi i metodi bottom up o top down.
Vedi questa discussione su memoization vs tabulazione.
Quindi la programmazione dinamica è un metodo per risolvere alcune classi di problemi risolvendo le relazioni / ricorsioni di ricorrenza e memorizzando soluzioni precedentemente trovate tramite tabulazione o memoizzazione. La memoizzazione è un metodo per tenere traccia delle soluzioni ai problemi precedentemente risolti e può essere utilizzata con qualsiasi funzione che abbia soluzioni deterministiche uniche per un determinato set di input.
La programmazione dinamica è spesso chiamata Memoization!
La memorizzazione è la tecnica top-down (inizia a risolvere il problema dato scomponendolo) e la programmazione dinamica è una tecnica bottom-up (inizia a risolvere dal banale sotto-problema, verso il problema dato)
DP trova la soluzione partendo dai casi di base e si sposta verso l'alto. DP risolve tutti i problemi secondari, perché lo fa dal basso verso l'alto
A differenza della Memoization, che risolve solo i sotto-problemi necessari
DP ha il potenziale per trasformare soluzioni di forza bruta a tempo esponenziale in algoritmi a tempo polinomiale.
DP può essere molto più efficiente perché è iterativo
Al contrario, la Memoization deve pagare le spese generali (spesso significative) dovute alla ricorsione.
Per essere più semplici, Memoization utilizza l'approccio top-down per risolvere il problema, ovvero inizia con il problema principale (principale), quindi lo suddivide in sotto-problemi e risolve questi sotto-problemi in modo simile. In questo approccio lo stesso sotto-problema può verificarsi più volte e consumare più cicli della CPU, quindi aumentare la complessità del tempo. Mentre nella programmazione dinamica lo stesso sotto-problema non verrà risolto più volte ma il risultato precedente verrà utilizzato per ottimizzare la soluzione.
(1) Memoization e DP, concettualmente , è davvero la stessa cosa. Perché: considera la definizione di DP: "sottoproblemi sovrapposti" "e sottostruttura ottimale". La memoizzazione possiede pienamente questi 2.
(2) La memorizzazione è DP con il rischio di overflow dello stack se la ricorsione è profonda. DP dal basso verso l'alto non presenta questo rischio.
(3) La memorizzazione richiede una tabella hash. Quindi spazio aggiuntivo e tempo di ricerca.
Quindi, per rispondere alla domanda:
- Concettualmente , (1) significa che sono la stessa cosa.
-Tenendo in considerazione (2), se proprio lo si desidera, la memoization è un sottoinsieme di DP, nel senso che un problema risolvibile con la memoization sarà risolvibile da DP, ma un problema risolvibile da DP potrebbe non essere risolvibile con la memoization (perché potrebbe sovrapporre lo stack).
-Tenuto conto di (3), presentano differenze minori nelle prestazioni.
Da Wikipedia:
Memoizzazione
Nell'informatica, la memoizzazione è una tecnica di ottimizzazione utilizzata principalmente per accelerare i programmi per computer facendo sì che le chiamate di funzione evitino di ripetere il calcolo dei risultati per input elaborati in precedenza.
Programmazione dinamica
In matematica e informatica, la programmazione dinamica è un metodo per risolvere problemi complessi scomponendoli in sottoproblemi più semplici.
Quando si suddivide un problema in sottoproblemi più piccoli / più semplici, spesso si riscontra lo stesso sottoproblema più di una volta, quindi si utilizza Memoization per salvare i risultati dei calcoli precedenti, quindi non è necessario ripeterli.
La programmazione dinamica incontra spesso situazioni in cui ha senso usare la memoizzazione ma puoi usare entrambe le tecniche senza necessariamente usare l'altra.
Sia Memoization che Dynamic Programming risolvono i singoli problemi secondari una sola volta.
La memoizzazione utilizza la ricorsione e funziona dall'alto verso il basso, mentre la programmazione dinamica si sposta nella direzione opposta risolvendo il problema dal basso verso l'alto.
Di seguito è un'interessante analogia:
Top-down - Per prima cosa dici che prenderò il controllo del mondo. Come lo farai? Dici che prenderò il controllo dell'Asia per primo. Come lo farai? Prenderò per primo l'India. Diventerò il Primo Ministro di Delhi, ecc. Ecc.
Bottom-up - Dici che diventerò il CM di Delhi. Poi prenderò il controllo dell'India, poi di tutti gli altri paesi dell'Asia e finalmente prenderò il controllo del mondo.
Vorrei andare con un esempio ;
Problema:
Stai salendo una scala. Ci vogliono n passi per raggiungere la cima.
Ogni volta puoi salire 1 o 2 gradini. In quanti modi diversi puoi salire in cima?
Ricorsione con Memoization
In questo modo stiamo potando (una rimozione di materiale in eccesso da un albero o un arbusto) albero di ricorsione con l'aiuto di una serie di memo e riducendo le dimensioni dell'albero di ricorsione fino a nn.
public class Solution {
public int climbStairs(int n) {
int memo[] = new int[n + 1];
return climb_Stairs(0, n, memo);
}
public int climb_Stairs(int i, int n, int memo[]) {
if (i > n) {
return 0;
}
if (i == n) {
return 1;
}
if (memo[i] > 0) {
return memo[i];
}
memo[i] = climb_Stairs(i + 1, n, memo) + climb_Stairs(i + 2, n, memo);
return memo[i];
}
}
Programmazione dinamica
Come possiamo vedere questo problema può essere suddiviso in sottoproblemi e contiene la proprietà di sottostruttura ottimale, ovvero la sua soluzione ottimale può essere costruita in modo efficiente da soluzioni ottimali dei suoi sottoproblemi, possiamo usare la programmazione dinamica per risolvere questo problema.
public class Solution {
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
Gli esempi traggono da https://leetcode.com/problems/climbing-stairs/
Pensa solo a due modi,
In Memoization andiamo con (1.) dove salviamo ogni chiamata di funzione in una cache e richiamiamo da lì. È un po 'costoso in quanto comporta chiamate ricorsive.
Nella Programmazione dinamica andiamo con (2.) dove manteniamo una tabella, dal basso verso l'alto risolvendo i sottoproblemi usando i dati salvati nella tabella, comunemente chiamati dp-table.
Nota:
Entrambi sono applicabili a problemi con sotto-problemi sovrapposti.
La memorizzazione avviene in modo relativamente scarso rispetto a DP a causa delle spese generali coinvolte durante le chiamate di funzione ricorsiva.
Nella programmazione dinamica ,
Nella memorizzazione ,