Bootstrap

(算法)买卖股票的最佳时期含⼿续费————<动态规划>

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];
	}
}
;