框架
思路:
明确dp数组的定义,dp[i][k][0]代表 第i天,至多交易K次,并且手上还有股票的最大利润
明确选择:每天都有三种「选择」:买入、卖出、无操作,我们用 buy, sell, rest 表示这三种选择
base case:
dp[-1][k][0] = dp[i][0][0] = 0
dp[-1][k][1] = dp[i][0][1] = -infinity
状态转移方程:
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
一次交易最大利润
class Solution {
public int maxProfit(int[] prices) {
//base case初始状态 dp[-1][0]=0,dp[-1][1]=-99999
int dp_i_0=0,dp_i_1=Integer.MIN_VALUE;
//设置一个变量保存前一个状态,使时间复杂度O(1)
int n=prices.length;
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;
}
}
尽可能多的交易
class Solution {
public int maxProfit(int[] prices) {
int n=prices.length;
int dp_i_0=0,dp_i_1=Integer.MIN_VALUE;
for(int i=0;i<n;i++){
int tmp=dp_i_0;
dp_i_0=Math.max(dp_i_0,dp_i_1+prices[i]);
dp_i_1=Math.max(dp_i_1,tmp-prices[i]);
}
return dp_i_0;
}
}
最多俩次交易
法1
class Solution {
public int maxProfit(int[] prices) {
int dp_i10 = 0, dp_i11 = Integer.MIN_VALUE;
int dp_i20 = 0, dp_i21 = Integer.MIN_VALUE;
for (int price : prices) {
dp_i20 = Math.max(dp_i20, dp_i21 + price);
dp_i21 = Math.max(dp_i21, dp_i10 - price);
dp_i10 = Math.max(dp_i10, dp_i11 + price);
dp_i11 = Math.max(dp_i11, -price);
}
return dp_i20;
}
}
法2
class Solution {
public int maxProfit(int[] prices) {
//dp[-1][k][0] = 0
//dp[-1][k][1] = -infinity
//dp[i][0][0] = 0
//dp[i][0][1] = -infinity
int max_k = 2;
int n=prices.length;
int[][][] dp = new int[n][max_k + 1][2];
if(n==0) return 0;
for (int i = 0; i < n; i++) {
for (int k = max_k; k >= 1; k--) {
if (i - 1 == -1) {
/*处理 base case */
dp[0][k][0]=0;
dp[0][k][1]=-prices[0];
continue;
}
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]);
}
}
// 穷举了 n × max_k × 2 个状态,正确。
return dp[n - 1][max_k][0];
}
}
多次交易含冷冻期
class Solution {
public int maxProfit(int[] prices) {
int n=prices.length;
int dp_i_0=0,dp_i_1=Integer.MIN_VALUE;
int dp_i_pre=0;//dp[i-2][0]
for(int i=0;i<n;i++){
int tmp=dp_i_0;
dp_i_0=Math.max(dp_i_0,dp_i_1+prices[i]);
dp_i_1=Math.max(dp_i_1,dp_i_pre-prices[i]);
dp_i_pre=tmp;
}
return dp_i_0;
}
}
多次交易含手续费
class Solution {
public int maxProfit(int[] prices, int fee) {
int n=prices.length;
int dp_i_0=0,dp_i_1=Integer.MIN_VALUE;
for(int i=0;i<n;i++){
int tmp=dp_i_0;
dp_i_0=Math.max(dp_i_0,dp_i_1+prices[i]);
dp_i_1=Math.max(dp_i_1,tmp-prices[i]-fee);
}
return dp_i_0;
}
}