Topic link: https: //leetcode-cn.com/problems/triangle/
Subject description:
Given a triangle, find the minimum and the top-down path. Each step can move to the next line adjacent nodes.
For example, given triangle:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
Top-down and minimum path 11 (i.e., 2 + 3 + 5 + 1 = 11).
Description:
If you can use only O (n) extra space (n number of rows as a triangle) to solve this problem, then your algorithm will be a plus.
Ideas:
My first idea is to use the DFS, top to bottom traversal of all paths, as shown below:
def minimumTotal(self, triangle: List[List[int]]) -> int:
self.res = float("inf")
row = len(triangle)
def helper(level, i, j, tmp):
if level == row:
self.res = min(self.res, tmp)
return
if 0 <= i < len(triangle[level]):
helper(level + 1, i, i+1, tmp + triangle[level][i])
if 0 <= j < len(triangle[level]):
helper(level + 1, j, j+1, tmp + triangle[level][j])
# 层level, 访问下一层两个节点位置i,j , 目前总和tmp
helper(0, -1, 0, 0)
return self.res
The above approach through all the paths, so time out, so we use DFS with memory (top-down dynamic programming),
def minimumTotal(self, triangle) -> int:
import functools
row = len(triangle)
@functools.lru_cache(None)
def helper(level, i, j):
if level == row:
return 0
res = 0
a = float("inf")
b = float("inf")
if 0 <= i < len(triangle[level]):
a = helper(level + 1, i, i + 1) + triangle[level][i]
if 0 <= j < len(triangle[level]):
b = helper(level + 1, j, j + 1) + triangle[level][j]
res += min(a, b)
return res
return helper(0, -1, 0)
Next, we use a bottom-up dynamic programming
We first use \ (O (n ^ 2) \) space, it is easier to understand
dp[i][j]
To go from top to bottom represents i,j
the value of the position of the minimum path.
Dynamic equation: dp[i][j] = min(dp[i-1][j], dp[i-1][j+1]) + triangle[i][j]
Of course, to be considered separately for the first and last.
def minimumTotal(self, triangle: List[List[int]]) -> int:
n = len(triangle)
if n == 0:
return 0
# 建dp空间
dp = [[0] * i for i in range(n)]
dp[0][0] = triangle[0][0]
for i in range(1, n):
for k in range(i + 1):
if k == 0:
dp[i][k] = dp[i - 1][k] + triangle[i][k]
elif k == i:
dp[i][k] = dp[i - 1][k - 1] + triangle[i][k]
else:
dp[i][k] = min(dp[i - 1][k - 1], dp[i - 1][k]) + triangle[i][k]
return min(dp[-1])
In fact, we only use dp every time a layer of data, if we backwards, upwards from the bottom can be optimized to \ (O (n) \) space
def minimumTotal(self, triangle: List[List[int]]) -> int:
row = len(triangle)
dp = [0] * row
for i in range(len(triangle[-1])):
dp[i] = triangle[-1][i]
#print(dp)
for i in range(row - 2, -1, -1):
for j in range(i + 1):
dp[j] = min(dp[j], dp[j + 1]) + triangle[i][j]
return dp[0]
java
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int row = triangle.size();
int[] dp = new int[row];
for (int i = 0; i < row; i++) dp[i] = triangle.get(row - 1).get(i);
for (int i = row - 2; i >= 0; i--)
for (int j = 0; j <= i; j++)
dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j);
return dp[0];
}
}