123. Best Time to Buy and Sell Stock III

123. Best Time to Buy and Sell Stock III

Hard

374492Add to ListShare

You are given an array prices where prices[i] is the price of a given stock on the ith day.

Find the maximum profit you can achieve. You may complete at most two transactions.

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

 

Example 1:

Input: prices = [3,3,5,0,0,3,1,4]
Output: 6
Explanation: 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.

Example 2:

Input: prices = [1,2,3,4,5]
Output: 4
Explanation: 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.

Example 3:

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

Example 4:

Input: prices = [1]
Output: 0

 

Constraints:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 105

 

超时代码- -||,保存一下

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        """
        assert Solution().maxProfit([8, 6, 4, 3, 3, 2, 3, 5, 8, 3, 8, 2, 6]) == 11
        assert Solution().maxProfit([2, 1, 4, 5, 2, 9, 7]) == 11
        assert Solution().maxProfit([1, 2, 3, 4, 5]) == 4
        assert Solution().maxProfit([8, 3, 6, 2, 8, 8, 8, 4, 2, 0, 7, 2, 9, 4, 9]) == 15
        assert Solution().maxProfit([2, 1, 2, 0, 1]) == 2
        assert Solution().maxProfit([2, 11, 10, 20, 15, 30]) == 33
        assert Solution().maxProfit([7, 1, 5, 2, 6, 0, 20, 1, 10]) == 29
        assert Solution().maxProfit([7, 1, 5, 2, 6]) == 8
        assert Solution().maxProfit([3, 3, 5, 0, 0, 3, 1, 4]) == 6
        assert Solution().maxProfit([7, 6, 4, 3, 1]) == 0

        解题思路:
        dp[n][2]保存前i个数为止取一个区间或2个区间的最优解
        start_index_list 保存所有递增序列开头下标
        min_index 代表最小数的下标

        1. 取一段区间
        dp[i][0] = max(dp[i-1][0], prices[i] - min_price),其中 0<i<n, min_price 为前i个出现的最小的数

        2. 取两段区间,枚举所有递增序列开头位置i,i左边的一段区间dp[i-1][0]最优解 + i到当前位置的区间
        dp[i][1] = max(dp[i][1] , dp[start_index-1][0] + prices[i] - prices[start_index]),
        其中 0 <= start_index < i < n, start_index 代表一个递增序列开头下标

        时间复杂度:最坏一直驼峰 O(n^2),空间复杂度:O(n)
        """

        n = len(prices)
        if prices is None or n <= 1:
            return 0
        dp = [[0 for col in range(2)] for row in range(n)]
        start_index_list = list()
        min_index = 0
        for i in range(1, n):
            # 1
            dp[i][0] = max(dp[i - 1][0], prices[i] - prices[min_index])

            if (i + 1 < n) and (prices[i + 1] >= prices[i] < prices[i - 1]):
                # 当前位置为递增起始位置,比左右小
                start_index_list.append(i)

            # 2
            dp[i][1] = dp[i - 1][1]
            if (i == n - 1) or (prices[i + 1] < prices[i]):
                # 优化:最后一个数或下一个数比当前的小才更新
                for j in range(len(start_index_list) - 1, -1, -1):
                    start_index = start_index_list[j]
                    if start_index < min_index:
                        # 做个剪枝,小于最小值前面的都不用遍历了
                        break
                    dp[i][1] = max(dp[i][1], dp[start_index - 1][0] + prices[i] - prices[start_index])

            if prices[i] < prices[min_index]:
                min_index = i

        return max(dp[n - 1][0], dp[n - 1][1])

 

AC

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        """
        assert Solution().maxProfit([8, 3, 6, 2, 8, 8, 8, 4, 2, 0, 7, 2, 9, 4, 9]) == 15
        assert Solution().maxProfit([8, 6, 4, 3, 3, 2, 3, 5, 8, 3, 8, 2, 6]) == 11
        assert Solution().maxProfit([2, 1, 4, 5, 2, 9, 7]) == 11
        assert Solution().maxProfit([1, 2, 3, 4, 5]) == 4
        assert Solution().maxProfit([2, 1, 2, 0, 1]) == 2
        assert Solution().maxProfit([2, 11, 10, 20, 15, 30]) == 33
        assert Solution().maxProfit([7, 1, 5, 2, 6, 0, 20, 1, 10]) == 29
        assert Solution().maxProfit([7, 1, 5, 2, 6]) == 8
        assert Solution().maxProfit([3, 3, 5, 0, 0, 3, 1, 4]) == 6
        assert Solution().maxProfit([7, 6, 4, 3, 1]) == 0

        解题思路:由121. Best Time to Buy and Sell Stock I 知,对于一段区间,
        用f[i]表示0~i为止最大值,只需要遍历一次。此题同理,但是允许最多2段区间。
        所以,设g[i]表示i~n为止最大值,结果为max{f(i)+g(i)}
        时间复杂度;O(n),空间复杂度:O(n)
        """
        if prices is None:
            return 0
        n = len(prices)
        if n <= 1:
            return 0
        f = [0] * n
        min_price = prices[0]
        for i in range(1, n):
            f[i] = max(f[i - 1], prices[i] - min_price)
            min_price = min(min_price, prices[i])
        g = [0] * n
        max_price = prices[n - 1]
        for i in range(n - 2, 0, -1):
            g[i] = max(g[i + 1], max_price - prices[i])
            max_price = max(max_price, prices[i])
        res = 0
        for i in range(n):
            res = max(res, f[i] + g[i])
        return res

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值