lintcode - 买卖股票的最佳时机 III

题目描述:假设你有一个数组,它的第i个元素是一支给定的股票在第i天的价格。设计一个算法来找到最大的利润。你最多可以完成两笔交易。

样例:给出一个样例数组 [4,4,6,1,1,4,2,5], 返回 6


之前,关于“买卖股票”的故事,我们已经讲过两集:买卖股票的最佳时机买卖股票的最佳时机 II

我默认你看这篇文章的时候,已经对前面两道题的方法彻底明白了。前面的第一道题关键是只能进行一次交易,第二道题的关键是可以进行任意次交易,而现在的问题是要进行两次交易,且只能进行两次交易。只能一次交易的时候,是根据数组特性,使用贪心法,任意次交易时,就更简单了,只要股票涨价,就交易,求总和即可。但是现在这种只能交易两次的情况,无疑,比前面的两道题都难。


可以这样来思考:既然我们已知进行一次交易的最大值了,那么,想要两次交易获得最大值,就存在以下可能的三种情况:在此之前,为了方便描述,我假设完成一次利润最大交易的开始时间为left,结束时间为right

1. 在left之前,进行一次交易,使得利润最大,这个最大利润加上left-right之间的利润,就是最终最大利润

2. 在right之后,进行一次交易,使得利润最大,这个最大利润加上left-right之间的利润,就是最终最大利润

3. 在left-right之间去掉最大损失,这样把left-right分成两段,这两段的利润和就是最大利润


换句话说,我们需要做的是求出上面3中情况的值,求他们的最大值。而left-right之间的最大损失的计算方法与最大利润的计算方法是极为相似的,不再赘述。


代码如下:

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):

        result1 = self.profit(prices)
        left, right = result1[0], result1[1]

        r1 = self.profit(prices[:left])[-1] + result1[-1]
        r2 = self.profit(prices[right + 1:])[-1] + result1[-1]
        r3 = result1[-1] - self.loss(prices[left + 1: right])

        return max(r1, r2, r3)

    def profit(self, prices):

        n = len(prices)
        if n < 2:
            return [0, 0, 0]

        sum_val, max_val = 0, 0
        left, right = 0, 1

        # 将可能成为left的值存储为temp
        temp = left

        for i in range(n - 1):

            sum_val += prices[i + 1] - prices[i]

            # 获得更大利润了,更新left, right以及max_val
            if sum_val > max_val:
                right = i + 1
                left = temp
                max_val = sum_val

            sum_val = max(0, sum_val)

            # 说明上一步中,sum_val <= 0,需更新temp
            if sum_val == 0:
                temp = i + 1

        # 返回左右值及最大利润
        return [left, right, max_val]

    def loss(self, prices):

        n = len(prices)
        if n < 2:
            return 0

        sum_val, min_val = 0, 0

        for i in range(n - 1):
            sum_val += prices[i + 1] - prices[i]
            min_val = min(min_val, sum_val)
            sum_val = min(0, sum_val)
            
        return min_val


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值