转换思维:
题目说使得卖出股票的利益最大,那么也可以理解成使得自己的现金最大(经过买入和卖出后),那么是不是应该在最便宜的时候买入,最贵的时候卖出,这样就把问题转换为求买入股票后自己的剩余现金最大,卖出后自己的现金依然最大的问题了。
1.确定dp数组和下标含义
dp[i][0]:第i天所持有股票时,你的现金数
dp[i][1]:第i天不持有股票时,你的现金数
2.确定递推公式
第i天持有股票dp[i][0],可以由两个状态推出
-
dp[i-1][0]:第i-1天就持有股票,那么第i天的现金就为第i-1天的现金数
-
-price[i]:第i-1天不持有现金,那么第i天的现金就为第i的买股票后剩余的现金数
目的是使得买入后自己剩余现金最大,所以就求两个状态的最大值
dp[i][0] = max(dp[i-1][0],-price[i])
第i天不持有股票dp[i][1],可以由两个状态推出
-
dp[i-1][1]:第i-1天不持有股票,那么第i天的现金就为昨天的现金数
-
price[i]+dp[i-1][0]:第i天卖出股票,那么第i天的现金就为卖出股票的现金加上i-1天持有股票的现金数
dp[i][1] = max(dp[i-1][1],prices[i] + dp[i-1][0])
3.dp数组初始化
由于dp[i-1][0]和dp[i-1][1]都是从第一列推出的,所以初始化dp[0][0]和dp[0][1]即可
dp[0][0]:第0天持有股票的现金,由于这是第一天,所以该天的现金就为买入股票后剩余现金 -price[0]
dp[0][1]:第0天不持有股票的现金,由于第一天不持有的话,那么该天的现金就为现金起始值,就是0
4.确定递推顺序
从递推公式可以看出dp[i]都是有dp[i - 1]推导出来的,那么⼀定是从前向后遍历
5.举例推导dp数组
用示例1,输⼊:[7,1,5,3,6,4]为例,dp数组状态如下:
dp[i][0] | dp[i][1] | |
---|---|---|
0 | -7 | 0 |
1 | -1 | 0 |
2 | -1 | 4 |
3 | -1 | 4 |
4 | -1 | 5 |
5 | -1 | 5 |
可以看到,dp[i][1]为最终结果,含义就是第5天不持有股票时的现金数
案例2的状态
代码
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
//定义dp数组
int[][] dp = new int[len][2];
//初始化dp数组
dp[0][0] = -prices[0];
dp[0][1] = 0;
for (int i=1; i<len; i++) {
//第i天持有股票时的现金数 i-1天时持有或者i天买入
dp[i][0] = Math.max(dp[i-1][0],-prices[i]);
//第i天不持有股票的现金数
dp[i][1] = Math.max(dp[i-1][1],prices[i] + dp[i-1][0]);
}
return dp[len-1][1];
}
}