LeetCode 120. 三角形最小路徑和 | Python
120. 三角形最小路徑和
題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/triangle
題目
給定一個三角形,找出自頂向下的最小路徑和。每一步只能移動到下一行中相鄰的結點上。
相鄰的結點 在這裡指的是 下標 與 上一層結點下標 相同或者等於 上一層結點下標 + 1 的兩個結點。
例如,給定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自頂向下的最小路徑和為 11(即,2 + 3 + 5 + 1 = 11)。
解題思路
思路:遞迴,動態規劃
首先先看題目中的提示,【相鄰的結點 在這裡指的是 下標 與 上一層結點下標 相同或者等於 上一層結點下標 + 1 的兩個結點
我們設 f(i, j)
為點 (i, j)
到底部的最小路徑和。現在根據上面這個提示,可以很容易得到公式:
f(i, j) = min(f(i+1, j), f(i+1, j+1)) + triangle[i][j]
也就是說,要求的路徑和為:取當前結點相鄰的兩個結點最小值,加上當前結點的值。
遞迴
先嚐試使用遞迴的方法求解,根據上面的公式,直接貼上程式碼:
class Solution: def minimumTotal(self, triangle: List[List[int]]) -> int: return self.path(triangle, 0, 0) def path(self, triangle, i, j): # 設定終止條件 if i == len(triangle): return 0 # 直接使用公式 return min(self.path(triangle, i+1, j), self.path(triangle, i+1, j+1)) + triangle[i][j]
上面的程式碼執行超時,因為進行了大量的重複計算,現在考慮進行優化。
遞迴(優化)
在這裡,採用建立備忘錄的方法,避免重複的計算,同樣這裡貼上程式碼:
class Solution: def minimumTotal(self, triangle: List[List[int]]) -> int: # 備忘錄 memo = {} def path(triangle, i, j): # 設定終止條件 if i == len(triangle): return 0 if (i, j) in memo: return memo[(i, j)] memo[(i, j)] = min(path(triangle, i+1, j), path(triangle, i+1, j+1)) + triangle[i][j] # 直接使用公式 return min(path(triangle, i+1, j), path(triangle, i+1, j+1)) + triangle[i][j] return path(triangle, 0, 0)
上面的方法都是自頂向下的,現在我們嘗試使用動態規劃,實現自底向上求解。
動態規劃
使用動態規劃的解法,先進行狀態定義。
狀態定義
設 dp[i][j]
為點 (i, j)
到底部的最小路徑和。
狀態轉移方程
同樣的,我們根據最開始得出的公式,可以得到狀態轉移方程為:
dp[i][j] = min(dp[i+1][j], dp[i+1][j+1]) + triangle[i][j]
具體程式碼實現見【程式碼實現 # 動態規劃】
動態規劃(空間優化)
上面的動態規劃演算法中,我們定義的是一個二維陣列。當我們計算 dp[i][j]
的時候,用到的是下一行的 dp[i+1][j]
和 dp[i+1][j+1]
。那我們可以直接考慮從底部往上,定義一個一維陣列。
具體程式碼實現見【程式碼實現 # 動態規劃(空間優化)】
程式碼實現
# 動態規劃
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
m = len(triangle)
dp = [[0] * (m+1) for _ in range(m+1)]
for i in range(m-1, -1, -1):
for j in range(0, i+1):
dp[i][j] = min(dp[i+1][j], dp[i+1][j+1]) + triangle[i][j]
return dp[0][0]
# 動態規劃(空間優化)
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
m = len(triangle)
dp = [0] * (m+1)
for i in range(m-1, -1, -1):
for j in range(0, i+1):
dp[j] = min(dp[j], dp[j+1]) + triangle[i][j]
return dp[0]
實現結果
動態規劃(優化前)
歡迎關注
公眾號 【書所集錄】