大家好,今天和大家分享一道动态规划的题目:最佳买卖股票时机含冷冻期,这道题目是一道熟悉的股票题,它是买卖股票的最佳时机的迭代版本。让我们一起来看看这道题目吧!
描述
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
思路
这道题目,关键点在于可以多次买卖+冷却时间
既然多次买卖,很明显不能用上面题目的思路,在区间上分析再用贪心是行不通的,只能求助于dp。dp题目的思路主要在于列出所有的可能性,然后用dp加速。
第一个版本
主函数不必多说,主要是看pro是怎么调用的。
pro(int[] a, int index, int buy)
这里的a是原数组,index是位置,buy是标记是否买入,相当于bollean,buy=-1 为true,反之为false。
public static int maxProfit(int[] prices) {
if(prices == null || prices.length < 1) return 0;
if(prices.length == 1) return 0;
if(prices.length == 2) return Math.max(prices[1] - prices[0],0);
// 表示从index=0开始,还没买入。
return pro(prices,0,-1);
}
// 从index位置开始,含有冷却值的最大收益
public static int pro(int[] a,int index,int buy){
//baseCase
if(index >= a.length) return 0;
int p1 = 0,p2 = 0;
// 还没有买入
if(buy == -1){
// mai
p1 = pro(a,index+1,index);
// bumai
p2 = pro(a,index+1,-1);
}else {
// 收益为负数直接跳过可能的两种判断,只有一种可能性,按照这个可能性直接返回
if(a[index] - a[buy] < 0) return pro(a,index+1,buy);
// 卖
p1 = (a[index] - a[buy]) + pro(a,index+2,-1);
// 不卖
p2 = pro(a,index+1,buy);
}
return Math.max(p1,p2);
}
dp方法
pro(int[] a,int index,int buy),先对pro进行参数分析,一个静态变量,两个可变变量。符合dp的二维简单结构。dp里面先赋默认值,
public static int maxProfit(int[] prices) {
if(prices == null || prices.length < 1) return 0;
if(prices.length == 1) return 0;
if(prices.length == 2) return Math.max(prices[1] - prices[0],0);
int[][] dp = new int[prices.length][prices.length+3];
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
dp[i][j] = -1;
}
}
return pro(prices,0,prices.length,dp);
}
// 加入dp记忆化
public static int pro(int[] a,int index,int buy,int[][] dp){
if(index >= a.length) return 0;
int p1 = 0,p2 = 0;
if(dp[index][buy] != -1) return dp[index][buy];
if(buy == a.length){
// mai
p1 = pro(a,index+1,index,dp);
// bumai
p2 = pro(a,index+1,buy,dp);
}else {
if(a[index] - a[buy] < 0) return pro(a,index+1,buy,dp);
// 卖
p1 = (a[index] - a[buy]) + pro(a,index+2,a.length,dp);
// 不卖
p2 = pro(a,index+1,buy,dp);
}
//dp[index][buy] = Math.max(Math.max(p1,p2),dp[index][buy]);
dp[index][buy] = Math.max(p1,p2);
return dp[index][buy];
}
可以再聊聊之前的那种,局部最优里面选择全局最优的贪心,在这道题目里面是不成立的。
比如 [2,4,1,12,20] ,如果用那种贪心,就是2 和 20,答案是18,也的确是最大。
但是比如[2,4,3,1,6],如果用这种贪心,就是2和6,收益是4。
如果我多买买股票,[2,4],[1,6]收益会更高,所以这种贪心依赖具体的数值关系,不成立。
而dp则是把所有的可能性都列出,从中选取最大值,因而成立。
感谢大家的收看,我们下期再见!