1. 题⽬链接:714.买卖股票的最佳时机含⼿续费
2. 题⽬描述:
3. 解法(动态规划):
算法思路:
1. 状态表⽰:
对于线性dp ,我们可以⽤「经验+题⽬要求」来定义状态表⽰:
i. 以某个位置为结尾,巴拉巴拉;
ii. 以某个位置为起点,巴拉巴拉。 这⾥我们选择⽐较常⽤的⽅式,以某个位置为结尾,结合题⽬要求,定义⼀个状态表⽰: 由于有「买⼊」「可交易」两个状态,因此我们可以选择⽤两个数组,其中:
▪ f[i] 表⽰:第i 天结束后,处于「买⼊」状态,此时的最⼤利润;
▪ g[i] 表⽰:第i 天结束后,处于「卖出」状态,此时的最⼤利润。
2. 状态转移⽅程:
我们选择在「卖出」的时候,⽀付这个⼿续费,那么在「买⼊」的时候,就不⽤再考虑⼿续费的问 题。
◦ 对于f[i] ,我们有两种情况能到达这个状态:
i. 在i - 1 天「持有」股票,第i 天啥也不⼲。此时最⼤收益为f[i - 1] ;
ii. 在i - 1 天的时候「没有」股票,在第i 天买⼊股票。此时最⼤收益为g[i - 1] - prices[i]) ; 两种情况下应该取最⼤值,因此f[i] = max(f[i - 1], g[i - 1] - prices[i]) 。
◦ 对于g[i] ,我们也有两种情况能够到达这个状态:
i. 在i - 1 天「持有」股票,但是在第i 天将股票卖出。此时最⼤收益为: f[i - 1] + prices[i] - fee) ,记得⼿续费;
ii. 在i - 1 天「没有」股票,然后第i 天啥也不⼲。此时最⼤收益为: g[i - 1] ; 两种情况下应该取最⼤值,因此g[i] = max(g[i - 1], f[i - 1] + prices[i] - fee) 。
3. 初始化:
由于需要⽤到前⾯的状态,因此需要初始化第⼀个位置。
◦ 对于f[0] ,此时处于「买⼊」状态,因此f[0] = -prices[0] ;
◦ 对于g[0] ,此时处于「没有股票」状态,啥也不⼲即可获得最⼤收益,因此g[0] = 0 。
4. 填表顺序:
毫⽆疑问是「从左往右」,但是两个表需要⼀起填。
5. 返回值:
应该返回「卖出」状态下,最后⼀天的最⼤值收益: g[n - 1] 。
C++算法代码:
class Solution
{
public:
int maxProfit(vector<int>& prices, int fee)
{
int n=prices.size();
//建表
vector<vector<int>>dp(n,vector<int>(2,0));
//初始化
//0为买入状态,1为卖出状态
dp[0][0]=-prices[0];
//填表
for(int i=1;i<n;i++)
{
dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);
dp[i][1]=max(dp[i-1][0]+prices[i]-fee,dp[i-1][1]);
}
//返回值
return max(dp[n-1][0],dp[n-1][1]);
}
};
Java算法代码:
class Solution
{
public int maxProfit(int[] prices, int fee)
{
// 1. 创建 dp 表
// 2. 初始化
// 3. 填表
// 4. 返回值
int n = prices.length;
int[] f = new int[n];
int[] g = new int[n];
f[0] = -prices[0];
for (int i = 1; i < n; i++)
{
f[i] = Math.max(f[i - 1], g[i - 1] - prices[i]);
g[i] = Math.max(g[i - 1], f[i - 1] + prices[i] - fee);
}
return g[n - 1];
}
}