题目:
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2] 输出: 3 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
思路:
动态规划就是通过状态转移公式,也就是 当前状态和 下一状态的对比,比出哪个更好就取用哪个。
对于这个题来说就是 sell的时候,其实就是比较 昨天卖比较好还是今天卖比较好,所以就是sell[i] = max(sell[i] , sell[i-1]),因为sell[i] =sell[i]就没意义了,所以这时候就要找一个sell[i]的替代品,所以推理一下第i天卖sell[i]就=当前价格price[i] - 从前一天算起的最合理买入价格buy[i-1]。由此可以推出一个状态转移方程 sell(i) = max(sell(i - 1) ,price(i) - buy(i - 1))。
同理 买入的时候就是比较今天买比较好还是昨天买比较好。buy[i] = max(buy[i] , buy[i - 1])--->max(buy[i - 1] , sell(i - 2) - price(i))。其中替换buy(i) 的sell(i - 2) - price(i) 的意思就是上一次卖出后 又买入挣得钱。为什么是sell(i -2)原因就是有一天的冻结期,如果没有冻结期的话就是sell(i - 1)了。
这时候再把 冻结期加上,因为冻结期就是因为前一天卖了,所以第二天才会冻结,所以cooldown(i) = sell(i - 1)。
所以先定义dp二维数组,因为有三个变量,所以用第二维用来区分(dp[i][0] 表示卖的时候可以挣的最多的钱,dp[i][1]表示买的时候可以挣的最多的钱,dp[i][2]表示冻结时期时候 能挣的最多的钱)
通过一个例子来逐步解释解释:
价格 1 2 3 0 1 0 6 冻结 0 0 1 2 2 2 2 卖出 0 1 2 2 2 2 8 比较前一天卖整的多还是当天买挣的多sell(i-1),sell(i)--> sell(i-1) buy(i-1)+price(i) 买入 -1 -1 -1 1 1 2 2 比较前一天买挣得多还是当天买挣得多buy(i-1),buy(i) --> buy(i-1) sell(i-2)-price(i)
代码:
public static int maxProfit(int[] prices) {
int[][] dp=new int[prices.length][3];
//添加边界判断条件
if(prices == null || prices.length < 2) return 0;
//定义三个数组,买的 卖的 冻结的时刻可以挣的最多的钱。
dp[0][0]=0;//sell
dp[0][1]= - prices[0];//buy
dp[0][2]=0;//cooldown
for(int i = 1 ;i < prices.length ;i++){
dp[i][0]=Math.max(dp[i - 1][0],dp[i - 1][1] + prices[i]);
dp[i][1]=Math.max(dp[i - 1][1],dp[i - 1][2] - prices[i]);
dp[i][2]=dp[i - 1][0];
}
return Math.max(dp[prices.length - 1][0],dp[prices.length - 1][2]);
}
结果: