1 题目
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [2,4,1], k = 2
输出: 2
解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
示例 2:
输入: [3,2,6,5,0,3], k = 2
输出: 7
解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。
随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2 Java
2.1 方法一(动归正向迭代)
class Solution {
/*
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
max( 选择 rest , 选择 sell )
今天没持股,两种可能,1今天没买,2今天刚卖
dp[i-1][k][0] 到 dp[i][k][0]:昨天没持股,今天也没持股(今天没买)
dp[i-1][k][1] 到 dp[i][k][0]:昨天持股了,今天没持股(今天刚卖)
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
max( 选择 rest , 选择 buy )
今天持股,两种可能,1今天没卖,2今天刚买
dp[i-1][k][1] 到 dp[i][k][1]:昨天持股,今天也持股(今天没卖)
dp[i-1][k-1][0] 到 dp[i][k][1]:昨天没持股,今天持股(今天刚买)
求dp[I][?][0],即最后一天,完成了?次交易,目前不持股,的收益,即为最大收益
买的当天,k会+1,持有变1
卖的当天,k不变,持有变0
本题k未知,作为参数传入,最多交易k次
*/
public int maxProfit(int k, int[] prices) {
if(prices.length == 0 || k == 0) return 0;
int I = prices.length, K = k + 1, J = 2;
// 若 k 相当于无限制,相当于题目股票II,直接贪心
if(2 * (K - 1) >= I) return maxProfitInfinit(prices);
// 若限制 k 次交易
return maxProfitLimit(k, prices);
}
// 若不限制交易次数(股票II贪心解法)
public int maxProfitInfinit(int[] prices) {
int profit = 0;
for(int i = 1; i < prices.length; i++){
// 今天比昨天高,就算利润
profit += Math.max(prices[i] - prices[i - 1], 0);
}
return profit;
}
// 若限制 k 次交易
public int maxProfitLimit(int kLimit, int[] prices){
int I = prices.length, K = kLimit + 1, J = 2;
// 创建初始化备忘录
int[][][] dp = new int[I][K][J];
for(int i = 0; i < Math.min(2 * (K - 1), I); i++){ // 暴力点就直接全部初始化-99999了
dp[i][0][0] = 0; // 注意
dp[i][0][1] = - 99999;
for(int k = 1; k < K; k++){
dp[i][k][0] = - 99999;
dp[i][k][1] = - 99999;
}
}
dp[0][1][1] = - prices[0]; // 注意
// 外层for状态步进
for(int i = 1; i < I; i++){
for(int k = 1; k < K; k++){ // k = 0的状态值都是0,一般不可能是解(没交易),没有计算的必要
// 内存for状态转移
dp[i][k][0] = Math.max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]);
dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i]);
}
}
// 选最大值,有可能交易1次比交易2次赚的多,并不是交易次数越多越好
int ans = 0;
for(int k = 1; k < K; k++) ans = Math.max(ans, dp[I - 1][k][0]);
return ans;
}
}
2.2 方法二()