给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例1
输入: [2,4,1], k = 2
输出: 2
解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
解题的关键在于根据状态进行穷举,具体到某一天,看看有哪些状态、再看看每个状态对应有哪些选择。
for 状态1 in 状态1的取值
for 状态2 in 状态2的取值
for ...
dp[状态1][状态2][...]=择优(选择1,选择2...)
在买卖股票问题中,每天都有三种选择,买入、卖出、无操作。其中买入和卖出是有先后顺序的,同时还有交易K次的限制。用第一个状态表示天数,第二个状态表示允许交易的次数,第三个状态是持有的状态(1表示持有,0表示未持有)
dp[i][k][0 or 1]
0<=i<=n-1,1<=k<=K n为天数,k为最多交易数
for(int i=0;i<n;i++){
for(int k=1;k<=K;k++){
for(int s=0;s<2;s++){
dp[i][k][s]=max(buy,sell,reset)
}
}
}
dp[1][1][1] 第一天,手上持有股票、还有一次交易机会。
最终想得到的答案是dp[n-1][K][0],即最后一天,最多允许K次交易,当前股票已卖出。
列出状态转移方程
dp[i][k][0]=max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
public class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
if (n == 0) {
return 0;
}
int[][] dp = new int[n][2];
for (int i = 0; i < n; i++) {
if (i - 1 == -1) {
dp[i][0] = 0;
dp[i][1] = -prices[i];
continue;
}
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
}
return dp[n - 1][0];
}
}
减少使用额外空间,简化代码
public class Solution1 {
public int maxProfit(int[] prices) {
int n = prices.length;
int dp_i_0 = 0;
int dp_i_1 = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
dp_i_1 = Math.max(dp_i_1, -prices[i]);
}
return dp_i_0;
}
}
public class Solution2 {
public int maxProfit(int[] prices) {
int n = prices.length;
if (n == 0) {
return 0;
}
int[][] dp = new int[n][2];
for (int i = 0; i < n; i++) {
if (i - 1 == -1) {
dp[i][0] = 0;
dp[i][1] = -prices[i];
continue;
}
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][0] - prices[i]);
}
return dp[n - 1][0];
}
}
public class Solution3 {
public int maxProfit(int[] prices) {
int n = prices.length;
int dp_i_0 = 0;
int dp_i_1 = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
int temp = dp_i_0;
dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
dp_i_1 = Math.max(dp_i_1, temp - prices[i]);
}
return dp_i_0;
}
}
public class Solution5 {
public int maxProfit(int[] prices) {
int n = prices.length;
if (n == 0) {
return 0;
}
int[][] dp = new int[n][2];
for (int i = 0; i < n; i++) {
if (i - 1 == -1) {
dp[i][0] = 0;
dp[i][1] = -prices[i];
continue;
}
if (i - 1 == 0) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
continue;
}
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 - 2][0] - prices[i]);
}
return dp[n - 1][0];
}
}