回答:
Programming.Guideの関連記事:動的プログラミングvsメモ化vs集計
メモ化と動的プログラミングの違いは何ですか?
メモ化とは、以前に計算された結果をキャッシュし、同じ計算が再び必要になったときにキャッシュされた結果を返す最適化手法を表す用語です。
動的計画法は、再帰的な性質の問題を反復的に解決する手法であり、副問題の計算が重複する場合に適用できます。
動的プログラミングは通常、集計を使用して実装されますが、メモ化を使用して実装することもできます。ご覧のとおり、どちらも他方の「サブセット」ではありません。
妥当なフォローアップの質問は次のとおりです。集計(典型的な動的プログラミング手法)とメモ化の違いは何ですか?
集計を使用して動的プログラミングの問題を解決するときは、問題を「ボトムアップ」で解決します。つまり、通常はn次元のテーブルを埋めて、関連するすべての副問題を最初に解決します。次に、表の結果に基づいて、「トップ」/元の問題の解決策が計算されます。
メモ化を使用して問題を解決する場合は、既に解決されたサブ問題のマップを維持することによってそれを行います。「トップ」問題を最初に解決するという意味で、「トップダウン」で実行します(通常、サブ問題を解決するために再帰します)。
ここからの良いスライド(リンクは死んでいますが、スライドはまだいいです):
- すべての副問題を少なくとも1回は解決する必要がある場合、ボトムアップの動的プログラミングアルゴリズムは、通常、トップダウンのメモ化されたアルゴリズムよりも一定の係数で優れています
- 再帰のオーバーヘッドがなく、テーブルのメンテナンスのオーバーヘッドが少ない
- 動的プログラミングアルゴリズムのテーブルアクセスの通常のパターンを利用して、時間またはスペースの要件をさらに削減できる問題がいくつかあります。
- サブ問題空間内の一部のサブ問題をまったく解決する必要がない場合、メモされたソリューションには、確実に必要なサブ問題のみを解決するという利点があります
追加のリソース:
動的計画法は、与えられた複雑な問題を副問題に分解して解決し、副問題の結果を保存して同じ結果を再度計算しないようにするアルゴリズムのパラダイムです。
http://www.geeksforgeeks.org/dynamic-programming-set-1/
メモ化は、以前に解決されたソリューション(多くの場合、配列に基づく集計とは対照的に、ハッシュキー値のペアとして実装されます)を追跡する簡単な方法です。ボトムアップ方式とトップダウン方式の両方で使用できます。
メモ化と集計のこの議論を参照してください。
したがって、動的プログラミングは、再帰関係/再帰を解決し、以前に見つかった解を表またはメモ化によって保存することにより、特定のクラスの問題を解決する方法です。メモ化は、以前に解決された問題の解決策を追跡する方法であり、特定の入力セットに対して一意の確定的解決策を持つ任意の関数で使用できます。
動的プログラミングはしばしばメモ化と呼ばれます!
メモ化はトップダウン手法であり(与えられた問題を分解することで解決します)、動的プログラミングはボトムアップ手法です(自明な副問題から、与えられた問題に向かって始めます)
DPは、ベースケースから始めてソリューションを見つけ、上に向かって進みます。DPはボトムアップで実行するため、すべてのサブ問題を解決します
必要なサブ問題のみを解決するメモ化とは異なり
DPには、指数時間ブルートフォースソリューションを多項式時間アルゴリズムに変換する可能性があります。
DPは反復的であるため、はるかに効率的かもしれません
反対に、メモ化は、再帰による(多くの場合、かなりの)オーバーヘッドを支払う必要があります。
より簡単にするために、メモ化はトップダウンアプローチを使用して問題を解決します。つまり、コア(メイン)の問題で始まり、サブ問題に分割して、これらのサブ問題を同様に解決します。このアプローチでは、同じサブ問題が複数回発生し、より多くのCPUサイクルを消費する可能性があるため、時間の複雑さが増します。一方、動的プログラミングでは、同じ副問題が複数回解決されることはありませんが、以前の結果がソリューションの最適化に使用されます。
(1)メモ化とDPは、概念的にはまったく同じものです。理由:DPの定義を検討してください:「重複するサブ問題」「最適なサブ構造」。メモ化はこれらを完全に所有します2。
(2)メモ化はDPであり、スタックオーバーフローのリスクは再帰が深いためです。DPボトムアップにはこのリスクはありません。
(3)メモ化にはハッシュテーブルが必要です。そのため、追加のスペース、およびいくつかのルックアップ時間。
だから質問に答えるために:
- 概念的に、(1)はそれらが同じものであることを意味します。
-(2)を考慮に入れ、本当に必要な場合、メモ化はDPのサブセットです。メモ化によって解決可能な問題はDPによって解決可能ですが、DPによって解決可能な問題はメモ化によって解決できない可能性があります(そのため)スタックオーバーフローの可能性があります)。
-(3)を考慮すると、パフォーマンスにわずかな違いがあります。
ウィキペディアから:
メモ化
コンピューティングでは、メモ化は、以前に処理された入力の結果の計算を繰り返さないように関数呼び出しを行うことにより、主にコンピュータープログラムを高速化するために使用される最適化手法です。
動的プログラミング
数学とコンピュータサイエンスでは、動的プログラミングは、複雑な問題をより簡単な部分問題に分解することによって解決する方法です。
問題をより小さな/より単純なサブ問題に分割するとき、同じサブ問題に2回以上遭遇することがよくあります。したがって、Memoizationを使用して以前の計算の結果を保存し、繰り返す必要がないようにします。
動的プログラミングでは、メモ化を使用するのが理にかなっている状況に遭遇することがよくありますが、どちらか一方の手法を使用する必要はありません。
メモ化と動的プログラミングはどちらも、個々の副問題を一度だけ解決します。
メモ化は再帰を使用してトップダウンで動作しますが、ダイナミックプログラミングは反対方向に移動して問題をボトムアップで解決します。
以下は興味深いアナロジーです-
トップダウン -まず、私が世界を引き継ぐと言います。どうするの?私が最初にアジアを引き継ぐとあなたは言う。どうするの?最初にインドを引き継ぎます。デリー首相などになります。
ボトムアップ -あなたは私がデリーのCMになると言います。それからインド、そしてアジアの他のすべての国、そして最後に私は世界を引き継ぎます。
私は一緒に行きたいと思い例。
問題:
あなたは階段を登っています。頂上に到達するにはnステップかかります。
毎回1つまたは2つの階段を登ることができます。あなたはどれだけ明確な方法で頂点に登ることができますか?
メモ化付きの再帰
このように、メモ配列を使用して再帰ツリーをプルーニング(ツリーまたは低木から余分なマテリアルを削除)し、再帰ツリーのサイズを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];
}
}
動的プログラミング
この問題はサブ問題に分解でき、最適なサブストラクチャプロパティが含まれていることがわかります。つまり、その最適解はサブ問題の最適解から効率的に構築できるため、動的プログラミングを使用してこの問題を解決できます。
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];
}
}
2つの方法を考えてください。
でメモ化私たちはそこからキャッシュ、コールバック内の各関数呼び出しを保存する(1)に行きます。再帰呼び出しが含まれるため、少し高価です。
では、動的プログラミング我々はテーブルを維持する(2)と一緒に行き、テーブルに保存されたデータを使用して部分問題を解くことによって、ボトムアップは、一般的にDP-テーブルと呼ば。
注意:
どちらも、重複するサブ問題の問題に適用できます。
再帰的な関数呼び出し中に発生するオーバーヘッドが原因で、メモ化はDPに比べてパフォーマンスが劣ります。