<p>You are given an array <code>prices</code> where <code>prices[i]</code> is the price of a given stock on the <code>i<sup>th</sup></code> day.</p>

<p>Find the maximum profit you can achieve. You may complete <strong>at most two transactions</strong>.</p>

<p><strong>Note:</strong> You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).</p>

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

<pre>
<strong>Input:</strong> prices = [3,3,5,0,0,3,1,4]
<strong>Output:</strong> 6
<strong>Explanation:</strong> Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.</pre>

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

<pre>
<strong>Input:</strong> prices = [1,2,3,4,5]
<strong>Output:</strong> 4
<strong>Explanation:</strong> Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.
</pre>

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

<pre>
<strong>Input:</strong> prices = [7,6,4,3,1]
<strong>Output:</strong> 0
<strong>Explanation:</strong> In this case, no transaction is done, i.e. max profit = 0.
</pre>

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

<ul>
	<li><code>1 &lt;= prices.length &lt;= 10<sup>5</sup></code></li>
	<li><code>0 &lt;= prices[i] &lt;= 10<sup>5</sup></code></li>
</ul>

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        ##### Bottom-Up
        import numpy as np
        T = len(prices)

        # States:
        # n = day number, at the beginning of each day, so go from 0 to total number of days, inclusive
        # k = number of buys up to that date
        # s = share held yes or no

        # Actions:
        # Buy
        # Sell
        # Do nothing

        # Max profit when you are not holding stock today at beginning of day n
        # bought 2 by beginning of day n
        # = didn't have stock yesterday + do nothing = dp[n-1][k][0]
        # = did have stock yesterday + sold = dp[n-1][k][1] + prices[n]
        # dp[n][2][0] = max of two above

        # bought <2 by beginning of day n
        # = didn't have stock yesterday + do nothing = dp[n-1][k][0]
        # = did have stock yesterday + sold = dp[n-1][k][1] + prices[n]


        # Max profit when you are holding stock today at beginning of day n
        # = didn't have stock yesterday + bought = dp[n-1][k][0] - prices[n]
        # = did have stock yesterday + do nothing = dp[n-1][k][1]
        # dp[n][k][1] = max of two above

        # States
        # k=0, s=0
            # buy -> dp[t+1][1][1] - prices[t]
            # sell -> NA
            # do nothing -> dp[t+1][0][0]
        # k=0, s=1
            # buy -> NA
            # sell -> dp[t+1][0][0] + prices[t]
            # do nothing -> dp[t+1][0][1]
        # k=1, s=0
            # buy -> dp[t+1][2][1] - prices[t]
            # sell -> NA
            # do nothing -> dp[t+1][1][0]
        # k=1, s=1
            # buy -> NA
            # sell -> dp[t+1][1][0] + prices[t]
            # do nothing -> dp[t+1][1][1]
        # k=2, s=0
            # buy -> Not allowed
            # sell -> NA
            # do nothing -> dp[t+1][k=2][0]
        # k=2, s=1
            # buy -> NA
            # sell -> dp[t+1][k=2][0] + prices[t]
            # do nothing -> dp[t+1][k=2][1]
            
        # (k,s):
        # X (0,0) -> (1,1) - prices[t]
        # X (0,0) -> (0,0)
        # X (0,1) -> (0,0) + prices[t]
        # X (0,1) -> (0,1)
        # (1,0) -> (2,1) - prices[t]
        # X (1,0) -> (1,0)
        # X (1,1) -> (1,0) + prices[t]
        # X (1,1) -> (1,1)
        # X (2,0) -> (2,0)
        # X (2,1) -> (2,0) + prices[t]
        # (2,1) -> (2,1)

        # Invert it:
        # (0,0),(0,1)-prices[t] -> (0,0)
        # (0,1) -> (0,1)
        # (1,0),(1,1)+prices[t] -> (1,0)
        # (0,0)-prices[t],(1,1) -> (1,1)
        # (2,0),(2,1)+prices[t] -> (2,0)
        # (1,0)-prices[t],(2,1) -> (2,1)

        # Initialize matrix
        dp = [[[np.nan for _ in range(2)] for _ in range(3)] for _ in range(T+1)]

        # Base case:
        dp[0][0][0] = 0
        dp[0][0][1] = (-1) * float('inf')
        dp[0][1][0] = 0
        dp[0][1][1] = (-1) * float('inf')
        dp[0][2][0] = 0
        dp[0][2][1] = (-1) * float('inf')

        # Induction from day 0 to n
        for t in range(0,T):
            dp[t+1][0][0] = max(dp[t][0][0],dp[t][0][1]+prices[t])
            dp[t+1][0][1] = dp[t+1][0][1]
            dp[t+1][1][0] = max(dp[t][1][0],dp[t][1][1]+prices[t])
            dp[t+1][1][1] = max(dp[t][0][0]-prices[t],dp[t][1][1])
            dp[t+1][2][0] = max(dp[t][2][0],dp[t][2][1]+prices[t])
            dp[t+1][2][1] = max(dp[t][2][1],dp[t][1][0]-prices[t])
        
        dp
        return dp[T][2][0]
81678