原题
题解
方法一 动态规划
当然我们可以仿照leetcode123.买卖股票的最佳时机 III里面的方法来塑造一个三维的数组,三维的含义分别表示的是日期、完成交易的次数,以及现在持有的股数。按照惯例,我们要验证k是否大于最大可能的交易数目,可是遗憾的是,此方法缩小了k数目到一半的prices长度,仍然超内存。
(此方法空间复杂度是O((Math.min(k,p.l/2))^2),而由于运行过程需要遍历三维数组每一个元素,那么时间复杂度也一样)
失败的代码示例;
//超时超内存
class Solution {
public int maxProfit(int k, int[] prices) {
if(prices.length==0){return 0;}
k=Math.min(k,prices.length/2);
//三维分别表示,日期、完成的交易数(0-k)、手中持股数
int daan=0;
int ans[][][]=new int[prices.length][k+1][2];
for(int i=0;i<prices.length;i++){
for(int j=0;j<=k;j++){
if(i==0){
ans[0][j][1]=-prices[0];
}
else{
if(j==0){
ans[i][0][1]=Math.max(ans[i-1][0][1],-prices[i]);
}
else{
ans[i][j][0]=Math.max(ans[i-1][j-1][1]+prices[i],ans[i-1][j][0]);
ans[i][j][1]=Math.max(ans[i-1][j][0]-prices[i],ans[i-1][j][1]);
}
}
}
}
for(int i=0;i<=k;i++){
daan=Math.max(daan,ans[prices.length-1][i][0]);
}
return daan;
}
}
既然这样,我们需要尽可能先减少动态规划中的空间消耗。我们何不不考虑日期,而只考虑交易完成的次数和手中的持股情况?
那么算法就变成了,建立一个二维数组,两个维度分别表示的是完成的交易数、手中的持股数。这样的话我们只需要消耗O(Math.min(k,p.l/2))的空间,时间复杂度是O(p.l*Math.min(k,p.l/2))
本思路java代码示例:
/*
@v7fgg
执行用时:170 ms, 在所有 Java 提交中击败了6.35%的用户
内存消耗:39.6 MB, 在所有 Java 提交中击败了11.11%的用户
2020年7月13日 14:02
*/
class Solution {
public int maxProfit(int k, int[] prices) {
if(prices.length==0||k==0){return 0;}
k=Math.min(k,prices.length/2);//防止超内存,最多k次交易
int daan=0;
//ans[a][b]表示的是在某一天的时候,我已经完成了a此交易,手里攥着b股
int[][] ans=new int[k+1][2];
for(int i=0;i<k;i++){
ans[i][1]=-prices[0];
}
for(int j=1;j<prices.length;j++){
for(int i=k;i>0;i--){
ans[i][1]=Math.max(ans[i][0]-prices[j],ans[i][1]);
ans[i][0]=Math.max(ans[i-1][1]+prices[j],ans[i][0]);
}
ans[0][1]=Math.max(-prices[j],ans[0][1]);
}
for(int i=0;i<=k;i++){
daan=Math.max(daan,ans[i][0]);
}
return daan;
}
}
改为一维数组后,代码如下:
/*
@v7fgg
执行用时:437 ms, 在所有 Java 提交中击败了5.02%的用户
内存消耗:40 MB, 在所有 Java 提交中击败了11.11%的用户
2020年7月10日 16:48
*/
class Solution {
public int maxProfit(int k, int[] prices) {
if(prices.length==0||k==0){return 0;}
k=Math.min(k,prices.length/2);//防止超内存
int[] ans=new int[2*k];
int daan=0;
for(int i=0;i<2*k;i+=2){
ans[i]=-prices[0];
}
for(int j=1;j<prices.length;j++){
for(int i=2*k-1;i>=1;i--){
if(i%2==0){ans[i]=Math.max(ans[i-1]-prices[j],ans[i]);}
else{ans[i]=Math.max(ans[i-1]+prices[j],ans[i]);}
}
ans[0]=Math.max(ans[0],-prices[j]);
}
for(int i=0;i<2*k;i++){
daan=Math.max(daan,ans[i]);
}
return daan;
}
}