Leetcode 64:最小路徑和(最詳細的解法!!!)
阿新 • • 發佈:2019-02-18
給定一個包含非負整數的 m x n 網格,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和為最小。
**說明:**每次只能向下或者向右移動一步。
示例:
輸入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
輸出: 7
解釋: 因為路徑 1→3→1→1→1 的總和最小。
解題思路
這個問題通過遞迴很好解決,對於上面的例子來說。我們要知道1
開始的最小路徑,那麼我們只要知道周圍1
、3
的最小路徑即可,以此類推下去即可。我們這裡的邊界條件就是我們遞迴到底的時候,也就是
self.r, self.c = len(grid), len(grid[0])
row == self. r - 1 and col == self.c - 1
並且我們還要考慮右上角和左下角的情況,所以我們寫出這樣的程式碼。
class Solution:
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
if not grid:
return 0
self.r, self.c = len(grid), len(grid[0])
return self. _minPathSum(0, 0, grid)
def _minPathSum(self, row, col, grid):
if row == self.r - 1 and col == self.c - 1:
return grid[row][col]
if row + 1 < self.r and col + 1 < self.c:
return grid[row][col] + min(self._minPathSum(row, col + 1, grid), self._minPathSum( row + 1, col, grid))
if row + 1 < self.r:
return grid[row][col] + self._minPathSum(row + 1, col, grid)
if col + 1 < self.c:
return grid[row][col] + self._minPathSum(row, col + 1, grid)
但是這樣做存在著大量的重複運算(在哪呢?)。我們可以通過記憶化搜尋的方式來優化上面的問題。
class Solution:
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
if not grid:
return 0
self.r, self.c = len(grid), len(grid[0])
mem = [[0]*self.c for _ in range(self.r)]
return self._minPathSum(0, 0, grid, mem)
def _minPathSum(self, row, col, grid, mem):
if row == self.r - 1 and col == self.c - 1:
return grid[row][col]
if mem[row][col]:
return mem[row][col]
if row + 1 < self.r and col + 1 < self.c:
mem[row][col] = grid[row][col] + min(self._minPathSum(row, col + 1, grid, mem),\
self._minPathSum(row + 1, col, grid, mem))
return mem[row][col]
if row + 1 < self.r:
mem[row][col] = grid[row][col] + self._minPathSum(row + 1, col, grid, mem)
return mem[row][col]
if col + 1 < self.c:
mem[row][col] = grid[row][col] + self._minPathSum(row, col + 1, grid, mem)
return mem[row][col]
實際上我們這裡通過迭代的方式去寫這個問題更加簡潔。無非就是,先將第一行和第一列元素分別向後累加。
[
[1,4,5],
[2,5,1],
[6,2,1]
]
然後考慮,第二行和第二列以及之後的元素問題,例如上面列中的中間元素,我們要考慮左邊加過來和上面加下來,那個值更小min(4+5,2+5)
,同理以此類推。
class Solution:
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
if not grid:
return 0
r, c = len(grid), len(grid[0])
mem = [[0]*self.c for _ in range(self.r)]
mem[0][0] = grid[0][0]
for i in range(1, c):
mem[0][i] = grid[0][i] + mem[0][i - 1]
for i in range(1, r):
mem[i][0] = grid[i][0] + mem[i - 1][0]
for i in range(1, r):
for j in range(1, c):
mem[i][j] = grid[i][j] + min(mem[i - 1][j], mem[i][j - 1])
return mem[r - 1][c - 1]
class Solution:
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
if not grid:
return 0
self.r, self.c = len(grid), len(grid[0])
mem = [[0]*self.c for _ in range(self.r)]
return self._minPathSum(grid,0, 0, mem)
def _minPathSum(self, grid, row, col, mem):
if row == self.r - 1 and col == self.c - 1:
mem[row][col] = grid[row][col]
return mem[row][col]
if row == self.r - 1:
mem[row][col] = grid[row][col] + self._minPathSum(grid, row, col + 1, mem)
return mem[row][col]
if col == self.c - 1:
mem[row][col] = grid[row][col] + self._minPathSum(grid, row + 1, col, mem)
return mem[row][col]
if not mem[row][col]:
mem[row][col] = grid[row][col] + min(self._minPathSum(grid, row, col + 1, mem),
self._minPathSum(grid, row + 1, col, mem))
return mem[row][col]
這個問題也可以使用最短路徑演算法解決,但是有點大材小用了。
如有問題,希望大家指出!!!