题目描述:
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
解题思路:
读完题目,不难想到将解法往dp上靠,但是却感觉自己写不出转移方程。那这时我们不妨多读几遍题目,我们发现第i天结束时,它一共存在着三种状态,处于冷冻期,持有股票,不持有股票。任何一天都是这三种情况,而且都是与前一天的这三种情况相关联的,所以我们不妨可以把dp数组特殊化一点。
我们不妨造一个二维的dp数组,数组的第一维度代表当前是第几天,第二维度代表着当前天结束时处于哪种状态,0代表着处于冷冻期;1代表着持有股票;2代表着不持有股票。所以接下来我们就可以来推导我们的转移方程了:
【注意:】以下的状态都代表着第i天结束时的状态,理解为当天的最后一刻。并且在这里我将只要进行了售出操作,不仅第二天时冷冻期,该天剩下的时间也为冷冻期。
(1)如果第i天结束时处于冷冻期,这说明我们今天第i天,进行了股票的卖出操作,我们得到:dp[i][0] = dp[i-1][1] + prices[i];
(2)如果第i天结束时不持有股票,注意此时第i天不会去购入股票,那它存在以下情况:
①第i-1天就不持有股票
②第i-1天处于冷冻期
得到转移方程:dp[i][2] = Math.max(dp[i-1][2],dp[i-1][0]);
(3)如果第i天结束时持有股票,那它存在以下情况:
①第i-1天就持有股票
②第i-1天不持有股票,第i天当天购入的股票
得到转移方程:dp[i][1] = Math.max(dp[i-1][1],dp[i-1][2] - prices[i]);
那么根据上述的转移方程,我们最后要的答案应该是什么呢?
肯定是最后一天结束时处于冷冻期和处于不持有股票的情况下的大值。肯定不可能是持有股票的情况。
代码:
public class LC309 {
//时间复杂度O(n) 空间复杂度O(n)
//dp,比普通dp难度要大一些,因为每一天遇到的是三种情况,而不是单纯的两种
//面对第i天,我们不确定改天结束是处于冷冻期、持不持有股票,所以我们需要分情况讨论
//我们可以造一个二维dp数组,用来存取当前每一天结束时的三种不同的情况所对应的当前的最大利润
//该数组中的第一维,代表着是当前是第几天
//第二维,0代表着cooldown冷冻期;1代表着持有股票;2代表着不持有股票
public int maxProfit(int[] prices) {
//如果数组中仅存在一个元素,则不需要进行任何判断,直接返回0.
if (prices.length == 1){
return 0;
}
int ansProfit = 0;
int[][] dp = new int[prices.length + 10][3];
//设置初始值,即第1天结束时的三种情况分别对应的当前的最大利润
dp[0][0] = 0;
dp[0][1] = -prices[0];
dp[0][2] = 0;
for (int i = 1; i < prices.length; i++){
//如果第i天结束时处于冷冻期,则第i天一定卖出去,第i-1天一定持有股票
dp[i][0] = dp[i-1][1] + prices[i];
//如果第i天结束时不持有股票,即第i天不进行股票的买入,则存在以下情况
//1.第i-1天不持有股票
//2.第i-1天处于冷冻期
dp[i][2] = Math.max(dp[i-1][2],dp[i-1][0]);
//如果第i天持有股票,则存在以下情况
//1.第i-1天就持有股票
//2.第i-1天不持有股票,第i天才买入
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][2] - prices[i]);
}
//最大利润一定是最后一天处于以下两种情况下:
//1.最后一天结束时处于冷冻期
//2.最后一天结束时不持有股票
ansProfit = Math.max(dp[prices.length-1][0],dp[prices.length-1][2]);
return ansProfit;
}
public static void main(String[] args) {
LC309 obj = new LC309();
System.out.println(obj.maxProfit(new int[]{1,0,3,1,1,2,5}));
}
}