web-dev-qa-db-ja.com

メモ化と動的プログラミングの違いは何ですか?

メモ化と動的プログラミングの違いは何ですか?動的プログラミングはメモ化のサブセットだと思います。正しいですか?

213
Sanghyun Lee

メモ化と動的プログラミングの違いは何ですか?

メモ化は、以前に計算された結果をキャッシュし、同じ計算が再度必要になったときにキャッシュされた結果を返す最適化手法を説明する用語です。

ダイナミックプログラミングは、再帰的な問題を反復的に解決するための手法であり、部分問題の計算が重複する場合に適用できます。

動的プログラミングは、通常集計を使用して実装されますが、メモ化を使用して実装することもできます。ご覧のとおり、どちらももう一方の「サブセット」ではありません。


妥当なフォローアップの質問は次のとおりです:集計(典型的な動的プログラミング手法)とメモ化の違いは何ですか?

集計を使用してダイナミックプログラミングの問題を解決するとき、問題「bottom up」を解決します。つまり、通常、関連するすべての副問題を最初に解決することによって解決しますn-次元テーブルを作成します。表の結果に基づいて、「トップ」/元の問題の解決策が計算されます。

メモ化を使用して問題を解決する場合は、すでに解決済みのサブ問題のマップを維持することによって行います。 「top down」というのは、最初に「top」問題を解決するという意味で実行します(通常は再帰して下位の問題を解決します)。

からの良いスライド ここ (リンクは現在無効ですが、スライドはまだ良いです):

  • すべての副問題を少なくとも1回解決する必要がある場合、ボトムアップの動的プログラミングアルゴリズムは、通常、一定の係数でトップダウンのメモ化アルゴリズムよりも優れています。
    • 再帰のオーバーヘッドがなく、テーブルのメンテナンスのオーバーヘッドが少ない
    • 動的プログラミングアルゴリズムのテーブルアクセスの通常のパターンを利用して、時間またはスペースの要件をさらに削減できる問題がいくつかあります。
  • サブ問題スペース内のいくつかのサブ問題をまったく解決する必要がない場合、メモ化ソリューションには、明らかに必要なサブ問題のみを解決するという利点があります。

追加リソース:


これは記事として書き直されました here

320
aioobe

ダイナミックプログラミングは、特定の複雑な問題をサブ問題に分割することで解決し、サブ問題の結果を保存して同じ結果を再度計算しないようにするアルゴリズムパラダイムです。

http://www.geeksforgeeks.org/dynamic-programming-set-1/

メモ化は、以前に解決されたソリューション(多くの場合、配列に基づいた集計とは対照的に、ハッシュキー値のペアとして実装されます)を追跡する簡単な方法です。ボトムアップ方式またはトップダウン方式の両方で使用できます。

メモ化と集計については この説明 をご覧ください。

したがって、動的プログラミングは、再帰関係/再帰を解決し、集計またはメモ化を介して以前に見つかったソリューションを保存することにより、特定のクラスの問題を解決する方法です。メモ化は、以前に解決された問題の解決策を追跡する方法であり、特定の入力セットに対して一意の決定論的解決策を持つ任意の関数で使用できます。

42
Tom M

動的プログラミングはしばしばメモ化と呼ばれます!

  1. メモ化はトップダウン手法(特定の問題を分解することで解決を開始する)であり、動的プログラミングはボトムアップ手法(些細な副問題から特定の問題に向かって解決を開始する)です。

  2. DPは、ベースケースから開始して解決策を見つけ、上に向かって進みます。 DPはボトムアップで行うため、すべてのサブ問題を解決します

    必要な副問題のみを解決するメモ化とは異なります

  3. DPには、指数時間ブルートフォースソリューションを多項式時間アルゴリズムに変換する可能性があります。

  4. DPは反復的であるため、はるかに効率的です。

    それどころか、Memoizationは、再帰による(多くの場合、重要な)オーバーヘッドの代価を支払わなければなりません。

より簡単にするために、メモ化はトップダウンアプローチを使用して問題を解決します。つまり、コア(メイン)問題から始まり、それをサブ問題に分割し、これらのサブ問題を同様に解決します。このアプローチでは、同じ副問題が複数回発生し、CPUサイクルをより多く消費する可能性があるため、時間の複雑さが増します。一方、動的プログラミングでは、同じ副問題が複数回解決されることはありませんが、ソリューションを最適化するために以前の結果が使用されます。

12
Farah Nazifa

(1)メモとDP、概念的には、実際には同じものです。理由:DPの定義を検討してください:「重複する部分問題」「最適な部分構造」。メモ化はこれらを完全に備えています2。

(2)メモ化はDPであり、再帰が深いとスタックオーバーフローのリスクがあります。 DPボトムアップにはこのリスクはありません。

(3)メモ化にはハッシュテーブルが必要です。そのため、追加のスペースと検索時間がかかります。

質問に答えるために:

-概念的に、(1)は、それらが同じものであることを意味します。

-(2)を考慮すると、メモ化はDPのサブセットであり、メモ化によって解決可能な問題はDPによって解決できるという意味で、DPによって解決可能な問題はメモ化によって解決できない可能性があるという意味でスタックオーバーフローの可能性があります)。

-(3)を考慮すると、パフォーマンスにわずかな違いがあります。

8
PoweredByRice

ウィキペディアから:

メモ化

コンピューティングにおいて、メモ化は、関数呼び出しが以前に処理された入力の結果の計算を繰り返さないようにすることにより、主にコンピュータープログラムを高速化するために使用される最適化手法です。

動的プログラミング

数学とコンピューターサイエンスでは、動的プログラミングは複雑な問題をより単純な副問題に分解することで解決する方法です。

問題をより小さな/より単純なサブ問題に分割する場合、同じサブ問題に何度も遭遇することがよくあります。そのため、メモ化を使用して以前の計算の結果を保存し、それらを繰り返す必要はありません。

動的プログラミングでは、メモ化を使用するのが理にかなっている状況に遭遇することがよくありますが、どちらか一方のテクニックを使用しても、もう一方を使用する必要はありません。

6
yurib

メモ化と動的プログラミングの両方が、個々のサブ問題を一度だけ解決します。

メモ化は再帰を使用してトップダウンで動作しますが、動的プログラミングは反対方向に移動して問題をボトムアップで解決します。

以下は興味深いアナロジーです-

トップダウン-最初に、私が世界を引き継ぐと言います。どうしますか?あなたは私が最初にアジアを引き継ぐと言います。どうしますか?最初にインドを引き継ぎます。デリー等の首相になります。

ボトムアップ-あなたは私がデリーのCMになると言います。その後、インドを引き継ぎ、次にアジアの他のすべての国を引き継ぎ、最後に私が世界を引き継ぎます。

4

example ;で行きたい

問題:

あなたは階段に登っています。最上部に到達するにはnステップかかります。

毎回、1つまたは2つのステップを登ることができます。いくつの異なる方法でトップに登ることができますか?

enter image description here

メモ化を伴う再帰

このようにして、メモ配列を使用して再帰ツリーをプルーニング(ツリーまたは低木からの余分な素材の削除)し、再帰ツリーのサイズを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];
    }
}

例は https://leetcode.com/problems/climbing-stairs/ から取得します

1
Teoman shipahi