【第十六周】714. Best Time to Buy and Sell Stock with Transaction Fee

原题

Your are given an array of integers prices, for which the i-th element is the price of a given stock on day i; and a non-negative integer fee representing a transaction fee.

You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. You may not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.)

Return the maximum profit you can make.

Example 1:
Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
Output: 8
Explanation: The maximum profit can be achieved by:
Buying at prices[0] = 1
Selling at prices[3] = 8
Buying at prices[4] = 4
Selling at prices[5] = 9
The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

leetcode地址: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/description/

解题思路

题目大意:有一支股票,每天的价格都有变动。你每天都可以选择买入或者卖出中的一种操作;而且股票的最大持有数为1。每次卖出时,会收取固定的手续费。现在给出股票的价格序列以及手续费,求能够获取的最大利润。

这是典型的动态规划题型,其主要的难点就是在于定义“状态”以及找出状态转移方程。

我在一开始的思路是这样的:设定状态F(n)为n天内的最大利润。而状态转移方程是什么呢?
要获取最大利润,那么最后一天结束后,手里肯定没有股票。所以最后的一个操作就是“卖出”。既然有卖出,肯定就有买入。假设最后一次买入的日期为x,卖出的日期为y, 那么在第x天之前的最大利润是F(x-1),刚好是一个子状态。设价格表为V, 所以这时候的总利润就是F(x-1) + V(y) - V(x) - fee。我们把x与y的所有组合都计算一遍,就可以得出最大利润了。

通过以上分析,我们就可以列出状态转移方程:
F(n) = max(V(y) - V(x) - fee + F(x-1)) (1 < y <= n, 1 <= x < y)
根据分析,我高高兴兴地写出代码,然后提交: Time Limit Exceeded

分析一下以上算法的时间复杂度:对于x与y的组合,有(n^2)/ 2 种可能, 所以复杂度为O(n^2)。
很明显嘛,真正优秀的DP算法不应该有这么高的复杂度的。一定是有条件漏了没有考虑清楚。

然后我学习了讨论区的解析,发现只需要几行代码就可以解决问题,时间复杂度为O(n),空间复杂度为O(1)。
主要思路:用T[i][0]表示第i天,库存为0时的最大利润;T[i][1]表示第i天,库存为1时的最大利润。

状态转移方程:
T[i][0] = max(T[i-1][0], T[i-1][1] + V(i))
T[i][1] = max(T[i-1][1], T[i-1][0] - V(i))

具体解释可以看这里,内有此类型问题的一系列分析。
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/discuss/108870

代码

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int T_ik0 = 0, T_ik1 = -99999;  //初始化状态
        for (int price : prices) {
            int temp = T_ik0;
            T_ik0 = max(T_ik0, T_ik1 + price - fee);
            T_ik1 = max(T_ik1, temp - price);
        }
        return T_ik0;
    }
};

总结

1、正确的状态定义
2、从前往后求解,可以减少空间复杂度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值