|
1 | | -class Solution: |
2 | | - def minimumTotal(self, triangle: List[List[int]]) -> int: |
3 | | - for row in range(1, len(triangle)): |
4 | | - for col in range(row + 1): |
5 | | - smallest_above = math.inf |
6 | | - if col > 0: |
7 | | - smallest_above = triangle[row - 1][col - 1] |
8 | | - if col < row: |
9 | | - smallest_above = min(smallest_above, triangle[row - 1][col]) |
10 | | - triangle[row][col] += smallest_above |
11 | | - return min(triangle[-1]) |
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | + |
| 4 | +def minimum_total(triangle: list[list[int]]) -> int: |
| 5 | + """ |
| 6 | + Return the minimum path sum from top to bottom of a triangle. |
| 7 | +
|
| 8 | + Each step you may move to adjacent numbers on the row below. |
| 9 | + The input must be a proper triangle: len(row i) == i + 1. |
| 10 | +
|
| 11 | + >>> minimum_total([[2],[3,4],[6,5,7],[4,1,8,3]]) |
| 12 | + 11 |
| 13 | + >>> minimum_total([[-10]]) |
| 14 | + -10 |
| 15 | + >>> minimum_total([[1],[2,3]]) |
| 16 | + 3 |
| 17 | + >>> minimum_total([]) # doctest: +IGNORE_EXCEPTION_DETAIL |
| 18 | + Traceback (most recent call last): |
| 19 | + ValueError: triangle must be non-empty and well-formed |
| 20 | + >>> minimum_total([[1],[2]]) # malformed (second row length not 2) # doctest: +IGNORE_EXCEPTION_DETAIL |
| 21 | + Traceback (most recent call last): |
| 22 | + ValueError: triangle must be non-empty and well-formed |
| 23 | + """ |
| 24 | + # Basic validation: non-empty and proper "triangle" shape |
| 25 | + if not triangle or any(len(row) != i + 1 for i, row in enumerate(triangle)): |
| 26 | + raise ValueError("triangle must be non-empty and well-formed") |
| 27 | + |
| 28 | + # Start from the last row and fold upwards. |
| 29 | + # dp[j] will store the minimum path sum from row r to the bottom starting at column j. |
| 30 | + dp = triangle[-1][:] # copy so we don't mutate the input |
| 31 | + |
| 32 | + for r in range(len(triangle) - 2, -1, -1): |
| 33 | + for c in range(r + 1): |
| 34 | + dp[c] = triangle[r][c] + min(dp[c], dp[c + 1]) |
| 35 | + |
| 36 | + return dp[0] |
| 37 | + |
| 38 | + |
| 39 | +if __name__ == "__main__": |
| 40 | + import doctest |
| 41 | + |
| 42 | + doctest.testmod() |
0 commit comments