1. トピック: 64. 最小パス合計
説明:
負でない整数を含む mxn グリッドを指定して、パス上の数値の合計が最小になるように、左上隅から右下隅までのパスを見つけてください。
注: 一度に下または右に 1 ステップのみ移動できます。
例 1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
例 2:
输入:grid = [[1,2,3],[4,5,6]]
输出:12
ヒント:
- m == グリッドの長さ
- n == グリッド[i].length
- 1 <= m、n <= 200
- 0 <= グリッド[i][j] <= 200
2. 問題解決のアイデア
パスの方向は下または右のみであるため、グリッドの最初の行の各要素には左上の要素から右に移動することによってのみ到達でき、グリッドの最初の列の各要素には到達できます。左上隅からのみ到達する 隅の要素は下方向に移動を開始する このときのパスは一意であるため、各要素に対応する最小パスの和は、対応するパス上の数値の合計となります。
最初の行または列にない要素の場合は、その上にある隣接する要素から 1 ステップ下に移動するか、左に隣接する要素から右に 1 ステップ移動することで、その要素に到達できます。要素に対応するパスは、その上の隣接要素の合計と、左側の 2 つの隣接要素に対応する最小パスの合計の最小値に現在の要素の値を加えたものに等しくなります。各要素に対応する最小パスは、隣接する要素に対応する最小パスの和に関係するため、動的計画法を使用して解くことができます。
2D配列を作成する
最後に、グリッドの左上隅からグリッドの右下隅までの最小パスの合計である dp[m-1][n-1] の値が取得されます。
3. コード例
class Solution(object):
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
# 解法一, 空间优化
m, n = len(grid), len(grid[0])
for i in range(1, n): # 第一行初始化
grid[0][i] = grid[0][i] + grid[0][i - 1]
for i in range(1, m): # 第一列初始化
grid[i][0] = grid[i][0] + grid[i - 1][0]
for i in range(1, m): # 对剩下的格子进行填充
for j in range(1, n):
grid[i][j] = grid[i][j] + min(grid[i - 1][j], grid[i][j - 1])
return grid[-1][-1]
# 解法二
if not grid or not grid[0]:
return 0
rows, columns = len(grid), len(grid[0])
dp = [[0] * columns for _ in range(rows)]
dp[0][0] = grid[0][0]
for i in range(1, rows):
dp[i][0] = dp[i - 1][0] + grid[i][0]
for j in range(1, columns):
dp[0][j] = dp[0][j - 1] + grid[0][j]
for i in range(1, rows):
for j in range(1, columns):
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
return dp[rows - 1][columns - 1]
# 解法三
m, n = len(grid), len(grid[0])
# 状态定义:dp[i][j] 表示从 [0,0] 到 [i,j] 的最小路径和
dp = [[0] * n for _ in range(m)]
# 状态初始化
dp[0][0] = grid[0][0]
# 状态转移
for i in range(m):
for j in range(n):
if i == 0 and j != 0:
dp[i][j] = grid[i][j] + dp[i][j - 1]
elif i != 0 and j == 0:
dp[i][j] = grid[i][j] + dp[i - 1][j]
elif i != 0 and j != 0:
dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1])
# 返回结果
return dp[m - 1][n - 1]