【问题标题】:Memoization of Dynamic Programming动态规划的记忆
【发布时间】:2013-02-17 12:55:21
【问题描述】:

我正在尝试学习动态编程的记忆,我在 youtube 上观看麻省理工学院的视频,试图跟随它。我不知道如何将第 N 个值与数组进行比较。

int[] memo;
public int fib(int n) {
    int f = 0;

    if n is in memo then return memo[n] <----not sure how to code this line.

    if (n<=2) {
        f = 1;
    } else {
        f = fib(n-1) + fib(n-2);
    }

    memo[n] = f;
    return f;
}

【问题讨论】:

  • 你可以使用 java API 吗??
  • 注意这个概念叫做memoization(没有“r”)。我已相应地编辑了您的问题。

标签: java dynamic-programming memoization


【解决方案1】:

使用ArrayList

ArrayList<Integer> memo = new ArrayList<Integer>();

public int fib(int n) {
    if (memo.size() == 0)
       memo.add(0); // element 0 is never accessed
    return fib2(n);
}

private int fib2(int n) {
    int f = 0;

    if (n < memo.size())
       return memo.get(n);

    if (n<=2) {
        f = 1;
    } else {
       f = fib2(n-2) + fib2(n-1);
    }

    memo.add(f); // elements inserted in order
    return f;
}

用数组来做:

int[] memo;

public int fib(int n) {
    memo = new int[n+1]; // all initialized to 0
    return fib2(n);
}

private int fib2(int n) {
    int f = 0;

    if (memo[n] != 0)
       return memo[n];

    if (n <= 2) {
        f = 1;
    } else {
        f = fib2(n-2) + fib2(n-1);
    }

    memo[n] = f;
    return f;
}

【讨论】:

  • 我的数组出现 nullPointerException 错误。对于数组列表,数字不会超过 fib(5)。
  • @JavaStudent For array - 您可能没有第二个函数,例如上面的 fib 构造 memo 并调用原始函数。对于ArrayList - 似乎可以在我的机器上正确打印。你check 应该是什么值?
  • 好的,我知道我的号码哪里出错了。如果我没有添加 memo.add(0),那么在 fib(6) 之后,数字将从 1、1、2、3、5、7、19、21、50 跳跃。如果我们不打算使用它,为什么还需要 add(0)?
  • @JavaStudent 因为memo.get(n) = fib(n)(并且fib(0) 为0,但从未计算或用于此算法)。也可以删除memo.add(0) 并拥有memo[n-1] = fib(n)(进行适用的更改)。
  • 您的代码在fib 定义中缺少return 语句(您应该有return fib2(n);)。带有array 的代码声明了一个不够大的数组(它的大小应该是n+1,而不仅仅是n)。
【解决方案2】:

您可以使用-1 值初始化您的memo 数组,因为该算法永远不会在数组中插入-1

所以检查memo[i]是否已经被插入意味着你必须检查memo[i] != -1是否已经被插入。

注意:这个概念实际上叫做memoization

【讨论】:

  • 为什么不将其保留为默认值 0?数组中的任何初始化值都不会是 0。
  • 您可以使用Arrays.fill
  • @Dukeling 您可以保留 0,但您通常会主动设置一个虚拟值,即使该值是 0 也不会产生歧义。如果您的算法中存在错误或忘记了步骤,这将特别有用。
【解决方案3】:

您不能将数组与单个元素进行比较。

你可能想要的是,假设你有一个未计算值的 -1 虚拟值:

if (memo[n] != -1) return memo[n]

【讨论】:

    【解决方案4】:

    我喜欢在 Java 中使用 HashMap。根据我的经验,HashMap 让记忆化变得非常容易实现。 https://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html

    四个步骤:

    1. 获取基本情况

    2. 使用m.get(n) == null 检查是否已计算子问题。

    3. 如果 (2) 不成立,则递归计算并将其存储到 HashMap。

      HashMap的key是当前子问题identifier(在斐波那契的情况下是n strong>第 n 个斐波那契数列。 value 是解决未解决问题的递归调用。

    4. 如果 (2) 为真,则返回 m.get(n)。

    这是一个使用 4 个步骤的斐波那契示例:

    HashMap<Integer, Integer> memo = new HashMap<Integer,Integer>();
    
    int fib(int n) {
    
        //1. base case
        if (n <= 1) 
            return n; 
    
        //2. check if sub problem is computed yet.
        if (m.get(n) == null) {
    
            //3. if not, compute the sub problem.
            m.put(n, fib(n - 1) + fib(n - 2));
        }
    
        //4. if so, return the result. 
        return m.get(n); 
    }
    

    对于许多记忆问题,您可以使用相同的方法。

    【讨论】:

      【解决方案5】:

      奇怪的是,这个问题有 0 个赞,但有 4 个答案,我觉得其中没有一个真正令人满意。下面是一个使用 4 种不同方法的实现 + 测试并进行比较的示例:

      import java.util.ArrayList;
      import java.util.HashMap;
      
      public class Fib {
      
          // Straightforward implementation:
          public static int fib(int n) {
          if (n <= 1) {
              return n;
          }
          return fib(n - 1) + fib(n - 2);
          }
      
          // Using array:
          static int[] memoArray;
          public static int fibArray(int n) {
          memoArray = new int[n];
          return fibArrayHelper(n);
          }
          private static int fibArrayHelper(int n) {
          if (n <= 1) {
              return n;
          } else {
              if (memoArray[n - 2] != 0) {
              return memoArray[n - 2];
              }
              memoArray[n - 2] = fibArrayHelper(n - 2) + fibArrayHelper(n - 1);
              return memoArray[n - 2];
          }
          }
      
          // Using ArrayList:
          static ArrayList < Integer > memoArrayList = new ArrayList < Integer > ();
      
          public static int fibArrayList(int n) {
          return fibArrayListHelper(n);
          }
      
          private static int fibArrayListHelper(int n) {
          if (n <= 1) {
              return n;
          } else {
              if (n - 2 < memoArrayList.size())
              return memoArrayList.get(n - 2);
              else {
              memoArrayList.add(fibArrayListHelper(n - 2) + fibArrayListHelper(n - 1));
              return memoArrayList.get(n - 2);
              }
          }
          }
      
          // Using HashMap:
          static HashMap < Integer, Integer > memoHash = new HashMap < Integer, Integer > ();
      
          static public int fibHashMap(int n) {
          if (n <= 1)
              return n;
          if (memoHash.get(n) == null) {
              memoHash.put(n - 2, fibHashMap(n - 1) + fibHashMap(n - 2));
          }
          return memoHash.get(n - 2);
          }
      
      
          public static void main(String args[]) {
          long preTime, postTime;
          int x = 35;
      
          preTime = System.nanoTime();
          System.out.printf("%17s: %d", "fib(" + x + ")", fib(x));
          postTime = System.nanoTime();
          System.out.printf(", computed in %10d nanoseconds.\n", postTime - preTime);
      
          preTime = System.nanoTime();
          System.out.printf("%17s: %d", "fibArray(" + x + ")", fibArray(x));
          postTime = System.nanoTime();
          System.out.printf(", computed in %10d nanoseconds.\n", postTime - preTime);
      
          preTime = System.nanoTime();
          System.out.printf("%17s: %d", "fibArrayList(" + x + ")", fibArrayList(x));
          postTime = System.nanoTime();
          System.out.printf(", computed in %10d nanoseconds.\n", postTime - preTime);
      
          preTime = System.nanoTime();
          System.out.printf("%17s: %d", "fibHashMap(" + x + ")", fibHashMap(x));
          postTime = System.nanoTime();
          System.out.printf(", computed in %10d nanoseconds.\n", postTime - preTime);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-16
        • 1970-01-01
        • 1970-01-01
        • 2020-05-20
        • 2019-07-26
        • 2011-11-12
        相关资源
        最近更新 更多