Given a triangle represented as a nested list of integers, find the minimum path sum from the top to the bottom. At each step, you can only move to adjacent numbers on the row below. Adjacent numbers are defined as the numbers at the same index or the next index in the row below.
For example, consider the following triangle:
[ [2],
[3,4],
[6,5,7],
[4,1,8,3] ]
The minimum path sum is 2 + 3 + 5 + 1 = 11 (2 -> 3 -> 5 -> 1).
Another example:
[ [-10] ]
The minimum path sum is -10.
Constraints:
1 <= triangle.length <= 200
triangle[0].length == 1
triangle[i].length == triangle[i - 1].length + 1
-10^4 <= triangle[i][j] <= 10^4
Could you solve this problem with O(n) extra space, where n is the number of rows in the triangle?
The most straightforward approach is to explore all possible paths from the top to the bottom of the triangle and compute the sum of each path. Then, we can return the minimum of these sums.
def min_path_sum_recursive(triangle, row, col):
if row == len(triangle) - 1:
return triangle[row][col]
return triangle[row][col] + min(
min_path_sum_recursive(triangle, row + 1, col),
min_path_sum_recursive(triangle, row + 1, col + 1)
)
def minimumTotal_brute_force(triangle):
return min_path_sum_recursive(triangle, 0, 0)
O(2^n), where n is the number of rows in the triangle. Each element has two possible paths to take, resulting in exponential time complexity.
O(n), where n is the number of rows, due to the recursive call stack.
Dynamic programming can significantly optimize the solution by avoiding redundant calculations. We can use a bottom-up approach.
def minimumTotal_dp(triangle):
n = len(triangle)
dp = triangle[-1][:] # Initialize DP table with the last row
for i in range(n - 2, -1, -1):
for j in range(i + 1):
dp[j] = triangle[i][j] + min(dp[j], dp[j + 1])
return dp[0]
O(n^2), where n is the number of rows in the triangle. We iterate through each element of the triangle once.
O(n), where n is the number of rows, because the dp
array stores the minimum sums for the current row being processed.
The algorithm can be further optimized to use O(1) extra space (excluding the space used by the input triangle) by modifying the original triangle in place.
def minimumTotal_in_place(triangle):
n = len(triangle)
for i in range(n - 2, -1, -1):
for j in range(i + 1):
triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
return triangle[0][0]