<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?
from queue import PriorityQueue
class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:

        memo = [[float('inf') for _ in range(len(triangle[len(triangle) - 1]))] for _ in range(len(triangle))]
        
        #dfs 
        def rec(i, j):
            if i == len(triangle) - 1:
                return triangle[i][j]

            if i + 1 < len(triangle):
                cost1 = float('inf')
                cost2 = float('inf')

                if j + 1 < len(triangle[i + 1]):
                    if memo[i + 1][j + 1] != float('inf'):
                        cost1 = memo[i + 1][j + 1]
                    else:
                        cost1 = rec(i + 1, j + 1)
                
                if memo[i + 1][j] != float('inf'):
                    cost2 = memo[i + 1][j]
                else:
                    cost2 = rec(i + 1, j)

                min_cost = min(cost1, cost2) + triangle[i][j]
                memo[i][j] = min(memo[i][j], min_cost)
                return memo[i][j]

        
        return rec(0, 0) 

        




        # djikstra: fails with negative weight edge 
        # pq = PriorityQueue()

        # # node cost, total cost, pos
        # pq.put((triangle[0][0], (0, 0)))

        # while pq:
        #     min_total, node = pq.get()
        #     y, x = node[0], node[1]

        #     if y == len(triangle) - 1: 
        #         return min_total

        #     if y + 1 < len(triangle):
        #         if x + 1 < len(triangle[y + 1]):
        #             pq.put((min_total + triangle[y + 1][x + 1], (y + 1, x + 1)))

        #         pq.put((min_total + triangle[y + 1][x], (y + 1, x)))

        # return -1
19100