【问题标题】:Trouble understanding dynamic programming无法理解动态规划
【发布时间】:2016-06-18 01:24:23
【问题描述】:

我遇到了这个问题。给定一个三角形,找到从上到下的最小路径和。每一步你都可以移动到下一行的相邻数字。

 [
    [2],
   [3,4],
  [6,5,7],
 [4,1,8,3]
]

这是一个动态规划的例子。但是当我来锻炼时,对我来说这是一个非常困难或令人困惑的概念。我已经在线观看了视频和阅读教程,起初看起来很容易,但是当我遇到问题时,我完全迷失了。 所以我在网上找到了一个使用底层方法的解决方案:

public init minmumTotal(ArrayList<ArrayList<Integer>> triangle) {
       if (triangle.size() == 0 || triangle == null)
                   return 0;
     int[] dp = new int[triangle.size()+1]; // store each index’s total
       for (int i = triangle.size()-1; i >=0; i--) {
             for (int j = 0; j < triangle.get(i).size(); j++) {
                // first round: dp[j], dp[j+1] are both 0
               dp[j] = Math.min(dp[j], dp[j+1]) + triangle.get(i).get(j); 
             }
         }
             return dp[0];
         }

通过解决方案后似乎很容易。但这可以使用自上而下的方法来完成吗?有人可以解释为什么底部方法比自上而下方法更好吗?还有什么时候适合使用自上而下或自下而上?而且由于问题提到每个"Each step you may move to adjacent numbers on the row below." 这是否意味着每行在我进入下一行之前迭代整个列?

【问题讨论】:

    标签: java dynamic-programming


    【解决方案1】:

    我不确定这个解决方案是否算作动态编程,但我认为它非常有效。

    您可以从三角形底部开始,然后通过在三角形中向上移动来折叠它。对于下一行中的每个数字,添加其下方两个数字中最小的数字。当您到达顶部时,您将只有一个数字,这将是您的结果。所以你会得到这个:

    开始:

       2
      3 4
     6 5 7
    4 1 8 3
    

    第 1 步:

       2
      3 4
     7 6 10
    

    第 2 步:

       2
      9 10
    

    第 3 步:

       11
    

    【讨论】:

    • @marstan 为什么不采用自上而下的方法?
    • 我认为最好从底部开始,因为您最终只有一个数字。如果你从顶部开始,你最终会得到 4 个数字。然后,您需要在完成其他三个步骤后搜索最小值。
    【解决方案2】:

    有点离题,但如果您真的想以正确的方式处理 NullPointerExceptions,则该解决方案中的第一个 if 语句需要转过来。

    所以我尝试了一种自上而下的方法,但存在一些问题。

    首先,就像 marstran 已经说过的那样,你最后有更多的数字,需要做最少的搜索。

    其次,自下而上的方法使用一个额外的数组字段来确保它不会遇到 IndexOutOfBound 异常。我并没有真正找到一种自上而下的好方法(自下而上的方法的优点是你总是知道你有两个数字要查看(左孩子和右孩子),自上而下的方法有很多节点没有右或左父母)。所以还有几个额外的 if 语句。

    public static int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
        if (triangle == null || triangle.isEmpty()) return 0;
    
        int[] results = new int[triangle.size()];   
    
        for (int i = 0; i < triangle.size(); i++) {
            ArrayList<Integer> line = triangle.get(i);
    
            for (int j = line.size() - 1; j >= 0; j--) {
                if (j == 0) results[j] = line.get(j) + results[j];
                else if (j >= i) results[j] = line.get(j) + results[j - 1];
                else results[j] = line.get(j) + Math.min(results[j], results[j - 1]);
            }
        }
    
        int minimum = results[0];
        for (int i = 1; i < results.length; i++) {
            if (results[i] < minimum) {
                minimum = results[i];
            }
        }
    
        return minimum;
    }
    

    无论如何,这与我通过自上而下的方法所能获得的给定解决方案一样接近。

    请记住,没有人会强迫您只使用一维数组来获取结果。如果这个概念太难想出,你可以简单地使用二维数组。它会增加您需要编写的代码量,但可能更容易编写。

    【讨论】:

      猜你喜欢
      • 2014-08-08
      • 1970-01-01
      • 2016-07-01
      • 2012-03-26
      • 2013-11-27
      • 1970-01-01
      相关资源
      最近更新 更多