<p>You are given <code>n</code> balloons, indexed from <code>0</code> to <code>n - 1</code>. Each balloon is painted with a number on it represented by an array <code>nums</code>. You are asked to burst all the balloons.</p>

<p>If you burst the <code>i<sup>th</sup></code> balloon, you will get <code>nums[i - 1] * nums[i] * nums[i + 1]</code> coins. If <code>i - 1</code> or <code>i + 1</code> goes out of bounds of the array, then treat it as if there is a balloon with a <code>1</code> painted on it.</p>

<p>Return <em>the maximum coins you can collect by bursting the balloons wisely</em>.</p>

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

<pre>
<strong>Input:</strong> nums = [3,1,5,8]
<strong>Output:</strong> 167
<strong>Explanation:</strong>
nums = [3,1,5,8] --&gt; [3,5,8] --&gt; [3,8] --&gt; [8] --&gt; []
coins =  3*1*5    +   3*5*8   +  1*3*8  + 1*8*1 = 167</pre>

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

<pre>
<strong>Input:</strong> nums = [1,5]
<strong>Output:</strong> 10
</pre>

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

<ul>
	<li><code>n == nums.length</code></li>
	<li><code>1 &lt;= n &lt;= 300</code></li>
	<li><code>0 &lt;= nums[i] &lt;= 100</code></li>
</ul>

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        """
        3 1 5 8
        15
        40

        3 1 5 8
        3 5 8
        3 8
        3

        15, 3 8
        120
        24
        8

        1 2 4 1

        0
        2 + [1 2] + [2 4 1] = 10
        4 + [1 2 4] + [4 1] = 12

        1 7 2 3 1 8 2 3 6 2 1 = 24
        7 2 3 8 2 3 6 2 = 42
        7 3 8 2 3 6 2 = 48
        7 3 8 3 6 2 = 168
        7 8 3 6 2 = 144
        7 8 6 2 = 96
        7 8 2 = 112
        7 2 = 14
        7 = 7

        7 2 3 1 8 2 3 6 2 = 6
        42 6 24 16 48 36 36

        7 2 1 8 2 3 6 2 = 14
        14 16 16 48 36 36
        
        7 1 8 2 3 6 2 = 16
        56 16 48 36 36

        7 1 2 3 6 2

        """
        nums = [1] + [ele for ele in nums if ele > 0] + [1]
        n = len(nums)
        coins = [[0 for _ in range(n)] for _ in range(n)]

        def f(left, right):
            if left + 1 == right:
                return 0
            if coins[left][right] > 0:
                return coins[left][right]
            ans = 0
            for i in range(left+1, right):
                ans = max(
                    ans,
                    nums[left] * nums[i] * nums[right] + f(left, i) + f(i, right)
                )
            coins[left][right] = ans
            return ans

        return f(0, len(nums)-1)
22391