【问题标题】:Min Path Sum in Matrix- Brute Force矩阵中的最小路径和-蛮力
【发布时间】:2017-02-22 00:10:36
【问题描述】:

我正在解决以下问题:

给定一个由非负数填充的 m x n 网格,找到一条从左上角到右下角的路径,该路径最小化沿其路径的所有数字的总和。 注意:您只能在任何时间点向下或向右移动。

我最初的印象是,从网格中的每个位置,得到向右与向下的最小长度。但是,这给了我以下错误的答案:

Input:
[[1,2],[1,1]]
Output:
2
Expected:
3

直觉上,不知道我做错了什么。它也是非常简单的代码(我知道它没有被记忆——正在计划下一步)但直观地不确定出了什么问题。递归基本情况是有意义的,并且每个数字都被考虑在内。

def min_path_sum(grid)
    smallest_path(0, 0, grid)
end

def smallest_path(row, col, grid)
    return 0 if (row == grid.length || col == grid.first.length)
    current_val = grid[row][col]
    [current_val + smallest_path(row+1, col, grid), current_val + smallest_path(row, col+1, grid)].min #memoize here

end

【问题讨论】:

    标签: ruby algorithm recursion matrix


    【解决方案1】:

    您没有制定适当的终止条件。您只检查直到您点击任一右列或底行。您需要保持在界限内,但要继续直到击中右下角。您需要在界限内重复,直到达到两个限制。

    鉴于此,您的代码确实可以正常工作:它找到 2 到底行的路径,而不是 3 到右边缘的路径。你只需要教它完成这项工作。

    这足以让您找到解决方案吗?

    【讨论】:

      【解决方案2】:

      由于这是无环有向图上的最短路径问题,您可以使用标准的shortest path algorithm

      您还可以使用动态规划 ("DP),这可能是最有效的优化技术。我的答案实现了 DP 算法。

      最短路径或 DP 算法将大大优于枚举从左上角到右下角的所有路径。由于路径的数量随着数组的大小呈指数增长,简单的枚举只能用于中等大小的数组。

      DP算法的思路如下。让nm 分别为行数和列数。首先计算从最后一行的每一列到最后一行的最后一列的最短路径。这是一个简单的计算,因为对于这些元素中的每一个,只有一个到 [m-1, n-1] 的路径。从[m-1, n-2] 开始,我们只需返回[m-1, 0]

      接下来,我们计算从其他每一行中的每个元素到[m-1, n-1] 的最短路径,从倒数第二行 (m-2) 开始,然后返回到第一行 (0)。每行中的最后一个元素[i, n-1] 很容易计算,因为只能向下(到[i+1, n-1])。因此,从[i, n-1][m-1, n-1] 的最短路径首先是到[i+1, n-1],然后是从[i+1, n-1] 开始的最短路径,我们已经计算过了(当然包括它的长度)。从[i, n-1] 开始的最短路径长度是[i, n-1] 的“向下”距离加上从[i+1, n-1] 开始的最短路径长度。

      对于元素[i, j]、n-1,i j < m-1,我们计算右下角的最短路径,并选择两者中较短的一个。

      我们可以如下实现。

      代码

      def shortest_path(distance)
        last_row, last_col = distance.size-1, distance.first.size-1
        h = {}
        last_row.downto(0) do |i|
          last_col.downto(0) do |j|
             h_right = { min_path_len: distance[i][j][:r] + h[[i,j+1]][:min_path_len],
                         next_node: [i,j+1] } if j < last_col
             h_down  = { min_path_len: distance[i][j][:d] + h[[i+1,j]][:min_path_len],
                         next_node: [i+1,j] } if i < last_row
             g =
             case
             when i == last_row && j == last_col  
               { min_path_len: 0, next_node: nil }
             when i == last_row
               h_right
             when j == last_col
               h_down
             else
               [h_right, h_down].min_by { |f| f[:min_path_len] }
             end
             h[[i,j]] = g
          end
        end
        build_path(h)
      end
      
      def build_path(h)
        node = [0, 0]
        len = h[node][:min_path_len]
        arr = []
        while h[node][:next_node]
          arr << node
          node = h[node][:next_node]
        end
        [len, arr]
      end
      

      示例

      假设这些是相邻节点之间的距离。

      ● 4 ● 3 ● 1 ● 2 ●
      6   2   5   4   5
      ● 3 ● 4 ● 6 ● 3 ●
      1   3   4   2   3
      ● 6 ● 3 ● 1 ● 2 ●
      

      以散列数组的形式提供这些信息很方便。

      distance = [
        [{ r: 4, d: 6 }, { r: 3, d: 2 }, { r: 1, d: 5 }, { r: 2, d: 4 }, { d: 5 }],
        [{ r: 3, d: 1 }, { r: 4, d: 3 }, { r: 6, d: 4 }, { r: 3, d: 2 }, { d: 3 }],
        [{ r: 6  },      { r: 3 },       { r: 1 },       { r: 2 }]
      ]
      

      我们现在可以计算最短路径。

      p shortest_path distance 
        #=> [15, [[0, 0], [0, 1], [1, 1], [2, 1], [2, 2], [2, 3]]]
      

      最短路径由返回的数组的第二个元素给出。 15 是该路径的长度。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-20
        相关资源
        最近更新 更多