123. Best Time to Buy and Sell Stock III***

123. Best Time to Buy and Sell Stock III***

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/

题目描述

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most two transactions.

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

Example 1:

Input: [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: [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: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

解题思路

强烈推荐 Most consistent ways of dealing with the series of stock problems, 文章实在精彩啊, 将有关 Stock 的题总结了一遍, 探索了这些题之间的一致性.

C++ 实现 1

需要注意到的是, 一个隐含的影响 max profit 的因素是我们手中所拥有的股票数量. 因为在每一天我们所能采取的行动只有三种: sell, buy 以及 rest. 然而, 要完成 sell 这个过程, 必须手上拥有一份股票; 而要完成 buy 这个过程, 则必须保证手上没有任何股票. 因此, 倘若设置 T[i][k] 表示在进行最多 k 次交易的情况下在第 i 天所能获得最大收益, 那么它其实可以分成两个部分: T[i][k][0] 以及 T[i][k][1], 前者表示采取某种行动之后手上股票变成 0 份所在第 i 天所能获得的最大收益, 而后者表示采取某种行动之后手上股票变成 1 份在第 i 天所能获得的最大收益. 递推关系能写成:

Base cases:
T[-1][k][0] = 0, T[-1][k][1] = -Infinity
T[i][0][0] = 0, T[i][0][1] = -Infinity

Recurrence relations:
T[i][k][0] = max(T[i-1][k][0], T[i-1][k][1] + prices[i]) # sell
T[i][k][1] = max(T[i-1][k][1], T[i-1][k-1][0] - prices[i]) # buy

为了找到最大的收益, 我们只需要遍历 prices, 并不断更新 T[i][k][0] 以及 T[i][k][1], 而最后一天的最大收益就是 T[i][k][0], 手上是没有股票才能获得最大收益.

上面是通用的公式, 而题目中要求 K = 2, 此时, 递推公式变为:

T[i][2][0] = max(T[i-1][2][0], T[i-1][2][1] + prices[i])
T[i][2][1] = max(T[i-1][2][1], T[i-1][1][0] - prices[i])
T[i][1][0] = max(T[i-1][1][0], T[i-1][1][1] + prices[i])
T[i][1][1] = max(T[i-1][1][1], -prices[i])

实现代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        vector<int> T1(prices.size() + 1);
        T1[0] = 0;
        int s0 = 0, s1 = INT32_MIN;
        for (int i = 0; i < prices.size(); ++ i) {
            s0 = std::max(s0, s1 + prices[i]);
            s1 = std::max(s1, -prices[i]);
            T1[i + 1] = s0; 
        }
        s0 = 0, s1 = INT32_MIN;
        for (int i = 0; i < prices.size(); ++ i) {
            s0 = std::max(s0, s1 + prices[i]);
            s1 = std::max(s1, T1[i] - prices[i]);
        }
        return s0;
    }
};

作者的实现更贴近公式:

public int maxProfit(int[] prices) {
    int T_i10 = 0, T_i11 = Integer.MIN_VALUE;
    int T_i20 = 0, T_i21 = Integer.MIN_VALUE;
        
    for (int price : prices) {
        T_i20 = Math.max(T_i20, T_i21 + price);
        T_i21 = Math.max(T_i21, T_i10 - price);
        T_i10 = Math.max(T_i10, T_i11 + price);
        T_i11 = Math.max(T_i11, -price);
    }
        
    return T_i20;
}

C++ 实现 2

用数组 T 来保存每个 k - 1 的状态. 这个方便扩展到 K 为其他值的情况. 可能需要对 T 进行优化.

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int K = 2;
        // 实际上, 不论 K 为多大, T 设置为 (2, prices.size() + 1) 的大小就行了
        // 但这里为了理解方便, 就设置为 (K + 1, prices.size() + 1) 便于推广到 K != 2 的情况.
        vector<vector<int>> T(K + 1, vector<int>(prices.size() + 1, 0)); 
        int s0 = 0, s1 = INT32_MIN;
        for (int k = 0; k < K; ++ k) {
            s0 = 0, s1 = INT32_MIN;
            for (int i = 0; i < prices.size(); ++ i) {
                s0 = std::max(s0, s1 + prices[i]); // sell
                s1 = std::max(s1, T[k][i] - prices[i]); // buy
                T[k + 1][i + 1] = s0; 
            }
        }
        return s0;
    }
};
发布了227 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Eric_1993/article/details/103882367