leetcode123. Best Time to Buy and Sell Stock III

18 篇文章 0 订阅

It's not difficult to get the DP recursive formula:

 

dp[k, i] = max(dp[k, i-1], prices[i] - prices[j] + dp[k-1, j-1]), j=[0..i-1]

 

For k transactions, on i-th day,
if we don't trade then the profit is same as previous day dp[k, i-1];
and if we bought the share on j-th day where j=[0..i-1], then sell the share on i-th day then the profit is prices[i] - prices[j] + dp[k-1, j-1] .
Actually j can be i as well. When j is i, the one more extra item prices[i] - prices[j] + dp[k-1, j] = dp[k-1, i] looks like we just lose one chance of transaction.

 

I see someone else use the formula dp[k, i] = max(dp[k, i-1], prices[i] - prices[j] + dp[k-1, j]), where the last one is dp[k-1, j] instead of dp[k-1, j-1]. It's not the direct sense, as if the share was bought on j-th day, then the total profit of previous transactions should be done on (j-1)th day. However, the result based on that formula is also correct, because if the share was sold on j-th day and then bought again, it is the same if we didn't trade on that day.

 

So the straigtforward implementation is:

 

        public int MaxProfitDp(int[] prices) {
            if (prices.Length == 0) return 0;
            var dp = new int[3, prices.Length];
            for (int k = 1; k <= 2; k++)  {
                for (int i = 1; i < prices.Length; i++) {
                    int min = prices[0];
                    for (int j = 1; j <= i; j++)
                        min = Math.Min(min, prices[j] - dp[k-1, j-1]);
                    dp[k, i] = Math.Max(dp[k, i-1], prices[i] - min);
                }
            }

            return dp[2, prices.Length - 1];
        }

 

Time complexity is O(kn^2), space complexity is O(kn).
In the above code, min is repeated calculated. It can be easily improved as:

 

        public int MaxProfitDpCompact1(int[] prices) {
            if (prices.Length == 0) return 0;
            var dp = new int[3, prices.Length];
            for (int k = 1; k <= 2; k++) {
                int min = prices[0];
                for (int i = 1; i < prices.Length; i++) {
                    min = Math.Min(min, prices[i] - dp[k-1, i-1]);
                    dp[k, i] = Math.Max(dp[k, i-1], prices[i] - min);
                }
            }

            return dp[2, prices.Length - 1];
        }

 

Time complexity is O(kn), space complexity is O(kn).
If we slight swap the two 'for' loops:

 

        public int MaxProfitDpCompact1T(int[] prices) {
            if (prices.Length == 0) return 0;
            var dp = new int[3, prices.Length];
            var min = new int[3];
            Array.Fill(min, prices[0]);
            for (int i = 1; i < prices.Length; i++) {
                for (int k = 1; k <= 2; k++) {
                    min[k] = Math.Min(min[k], prices[i] - dp[k-1, i-1]);
                    dp[k, i] = Math.Max(dp[k, i-1], prices[i] - min[k]);
                }
            }

            return dp[2, prices.Length - 1];
        }

 

We need to save min for each transaction, so there are k 'min'.
We can find the second dimension (variable i) is only dependent on the previous one (i-1), so we can compact this dimension. (We can choose the first dimension (variable k) as well since it is also only dependent on its previous one k-1, but can't compact both.)

 

        public int MaxProfitDpCompact2(int[] prices) {
            if (prices.Length == 0) return 0;
            var dp = new int[3];
            var min = new int[3];
            Array.Fill(min, prices[0]);
            for (int i = 1; i < prices.Length; i++)  {
                for (int k = 1; k <= 2; k++) {
                    min[k] = Math.Min(min[k], prices[i] - dp[k-1]);
                    dp[k] = Math.Max(dp[k], prices[i] - min[k]);
                }
            }

            return dp[2];
        }

 

So time complexity is O(kn), space complexity becomes O(k).
In this case, K is 2. We can expand the array to all named variables:

 

        public int MaxProfitDpCompactFinal(int[] prices)  {
            int buy1 = int.MaxValue, buy2 = int.MaxValue;
            int sell1 = 0, sell2 = 0;

            for (int i = 0; i < prices.Length; i++) {
                buy1 = Math.Min(buy1, prices[i]);
                sell1 = Math.Max(sell1, prices[i] - buy1);
                buy2 = Math.Min(buy2, prices[i] - sell1);
                sell2 = Math.Max(sell2, prices[i] - buy2);
            }

            return sell2;
        }

 

We can also explain the above codes in other words. On every day, we buy the share with the price as low as we can, and sell the share with price as high as we can. For the second transaction, we integrate the profit of first transaction into the cost of the second buy, then the profit of the second sell will be the total profit of two transactions.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值