<p>Given a <code>triangle</code> array, return <em>the minimum path sum from top to bottom</em>.</p>

<p>For each step, you may move to an adjacent number of the row below. More formally, if you are on index <code>i</code> on the current row, you may move to either index <code>i</code> or index <code>i + 1</code> on the next row.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
<strong>Output:</strong> 11
<strong>Explanation:</strong> The triangle looks like:
   <u>2</u>
  <u>3</u> 4
 6 <u>5</u> 7
4 <u>1</u> 8 3
The minimum path sum from top to bottom is 2 + 3 + 5 + 1 = 11 (underlined above).
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> triangle = [[-10]]
<strong>Output:</strong> -10
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= triangle.length &lt;= 200</code></li>
	<li><code>triangle[0].length == 1</code></li>
	<li><code>triangle[i].length == triangle[i - 1].length + 1</code></li>
	<li><code>-10<sup>4</sup> &lt;= triangle[i][j] &lt;= 10<sup>4</sup></code></li>
</ul>

<p>&nbsp;</p>
<strong>Follow up:</strong> Could you&nbsp;do this using only <code>O(n)</code> extra space, where <code>n</code> is the total number of rows in the triangle?
class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        # n = len(triangle)
        # # Recursive code
        # # ans = self.solve(0, 0, triangle, n-1)
        # # # Memoization code
        # dp = [[float('inf') for i in range(n)] for i in range(n)]
        # ans = self.solve(0, 0, triangle, n-1, dp)
        # return ans
    
    # recursive code
    # def solve(self, i, j, triangle, n):
    #     if i == n:
    #         return triangle[i][j]
    #     if i < 0 or j < 0:
    #         return 0
    #     down = triangle[i][j] + self.solve(i+1, j, triangle, n)
    #     diag = triangle[i][j] + self.solve(i+1, j+1, triangle, n)
    #     return min(down, diag)

    # Memoization code
    # def solve(self, i, j, triangle, n, dp):
    #     if i == n:
    #         return triangle[i][j]
    #     if i < 0 or j < 0:
    #         return 0
    #     if dp[i][j] != float('inf'):
    #         return dp[i][j]
    #     down = triangle[i][j] + self.solve(i+1, j, triangle, n, dp)
    #     diag = triangle[i][j] + self.solve(i+1, j+1, triangle, n, dp)
    #     dp[i][j] = min(down, diag)
    #     return dp[i][j]

        # Tabulation without helper function
        n = len(triangle)
        dp = [[float('inf') for i in range(n)] for i in range(n)]

        for i in range(n-1, -1, -1):  # From the last row up to the first row
            for j in range(i+1):  # j should run from 0 to i (inclusive)
                if i == n-1:
                    # Initialize the last row of dp with the triangle values
                    dp[i][j] = triangle[i][j]
                else:
                    # Find the minimum of the two possible paths: down or diagonal down
                    down = triangle[i][j] + dp[i+1][j]  # Move straight down
                    diag = triangle[i][j] + dp[i+1][j+1]  # Move diagonally down
                    dp[i][j] = min(down, diag)  # Store the minimum sum

        # The top element will contain the minimum path sum
        return dp[0][0]
18300