算法学习 || 动态规划(买卖股票的最佳时机3)
买卖股票的最佳时机
leetcode链接
思路:
动态规划:
动规五部曲:
1.dp数组及其下标含义
dp数组为dp[ i ] [ j ]
i表示第i天,j表示0到4五种当天的状态,dp[ i ] [ j ]表示当天状态的利润
当天一共有五种状态:
1.从未持有股票,(可以省略)
2.第一次持有股票
3.第一次未持有股票
4.第二次持有股票
5.第二次未持有股票
注意:不要把买入卖出的动作与持有未持有的状态搞混
2,确定递推公式
第一次持有股票的状态:
包含两种情况:
1.先前买入,继续持有:dp[ i-1 ] [ 1 ]
2.当天买入:dp[ i-1 ][ 0 ] - prices[ i ]
两种情况取最大值
递推公式:dp [ i ][ 1 ] = max(dp[ i-1 ][ 0 ] - prices[ i ] ,dp[ i-1 ] [ 1 ]);
第一次未持有股票状态:
包含两种情况:
1.保持之前未持有的状态:dp [ i-1] [ 2 ]
2.之前买入,第i天卖出:dp[ i-1] [ 1 ] + prices[ i ]
两种情况取最大值
递推公式:dp [ i ] [ 2 ] =max(dp[ i - 1 ][ 1 ] + prices[ i ],dp[ i -1 ][ 2 ]);
第二次持有股票的状态:
包含两种情况:
1.经历第一次买卖之后,在当天之前买入,继续持有:dp[ i -1][ 3 ]
2.经历第一次买卖之后,当天买入:dp [ i-1][ 2 ] -prices[ i ]
两种情况取最大值
递推公式:dp [ i ][ 3 ] = max(dp[ i -1][ 2 ] - prices[ i ] ,dp[ i-1 ] [ 3 ]);
第二次未持有股票的状态
包含两种情况:
1.经历第一次买卖之后,在当天之前已经卖出,继续保持未持有:dp [ i-1] [ 4 ]
2.经历第一次买卖之后,在当天之前买入,当天卖出:dp[ i-1] [ 3 ] + prices[ i ]
两种情况取最大值
递推公式:dp [ i ] [ 2 ] =max(dp[ i - 1 ][ 3] + prices[ i ],dp[ i -1 ][ 4 ]);
3.dp数组的初始化:
因为从未持有股票,没有利润:dp[ 0 ] [ 0] = 0
第一次持有股票的状态:
第一次持有一定是支付股票的钱:dp[ 0 ] [ 1 ] = - prices[ i ]
第一次未持有股票状态:
第一次未持有,理解为当天买入,当天买入:dp[ 0 ][ 2 ] = 0
第二次持有股票的状态:
因为是第一天,当天买入,当天卖出, 0收益,之后买入,所以收益为负:dp[ 0 ][ 3 ] = -prices[ i ]
第二次未持有股票的状态
理解为两次买入卖出,收益为0:dp[ 0 ] [ 4 ] = 0
4.确定遍历顺序:
从前往后
代码
class Solution {
public:int maxProfit(vector<int>& prices) {if(prices.size() == 0)return 0;vector<vector<int>> dp(prices.size(),vector<int>(5,0));dp[0][1] = -prices[0];dp[0][3] = -prices[0];for (int i = 1; i < prices.size(); i++) {dp[i][0] = dp[i - 1][0];dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);}return dp[prices.size() - 1][4];}
};
反思与总结:
重要的是搞清楚每一天有多少种状态,对应的递推公式,其他与之前的买卖股票思路一致