class Solution {
public int maxProfit(int[] prices) {
/**
动态规划求解
*/
if(prices == null || prices.length ==0) return 0;
int n = prices.length ;
int[][] dp = new int[n][3];
/**
认清以下三个状态:
dp[i][0] 第i天收盘后手上还持有一只股票时的累计最大收益
dp[i][1] 第i天收盘后手上没有持有股票但是处于冷冻期时候的最大收益
dp[i][2] 第i天收盘后手上没有股票且不是冷冻期时候的累计最大收益
dp[0][0] = -prices[0] 还没卖,收益是负数
dp[0][1] dp[0][2] 没有意义 取值为0
*/
dp[0][0] = -prices[0];
// 第i天所做的所有操作都是取决于第i-1天的状态
for(int i =1;i<n;++i){
// 状态1,第i天手上持有股票,要么是i-1天手上就持有了,要么是i-1天手上没有并且不是冷冻期,那就第i天先买
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][2]-prices[i]);
// 状态2,第i天手上没有股票并且属于冷冻期,那么说明只有第i-1 天手上持有了股票,在第i天收盘前卖掉了,才能是冷冻期
dp[i][1] = dp[i-1][0] +prices[i];
// 状态3:没有股票且不是冷冻期,要么第i-1 天是冷冻期,要么不是冷冻期且没有持有股票
dp[i][2] = Math.max(dp[i-1][1],dp[i-1][2]);
}
return Math.max(dp[n-1][1],dp[n-1][2]); // 不考虑手上还有股票的情况,因为落袋才有收益
// 方法2 因为第i天只是与第i-1 天有关,所以不存取之前的状态
int n = prices.length;
int dp0 = -prices[0];
int dp1 = 0;
int dp2 = 0;
for(int i =1;i<n;++i){
int nextdp0 = Math.max(dp0,dp2-prices[i]);
int nextdp1 = dp0 + prices[i-1];
int nextdp2 = Math.max(dp1,dp2);
dp0 = nextdp0;
dp1= nextdp1;
dp2 = nextdp2;
}
return Math.max(dp1,dp2);
}
}
class Solution {
public int maxProfit(int[] prices, int fee) {
int n = prices.length;
// 利用优化后的数组 第i天分为持有和不持有的状态 0表示不持有 1 表示持有
int[] dp = new int[2];
dp[0] =0;
dp[1] = -prices[0];
for(int i = 1;i<n;++i){
int tmp = dp[0];
// 第i天不持有的状态 前一天可能持有也可能不持有
// 前一天不持有,就不变还是dp0,前一天持有说明当天卖出去了,收回了钱但是要减去手续费
dp[0] = Math.max(dp[0],dp[1]+prices[i]-fee);
// 第i天持有, 则可能是前一天持有 dp[1] 前一天不持有 tmp是前一天时候的收益
dp[1] = Math.max(dp[1],tmp-prices[i]);
}
return dp[0];
}
}
class Solution {
public int maxProfit(int[] prices) {
/**
由于最多完成两笔交易,因此在任意一天结束后,会处于以下五种状态
1、未进行任何交易
2、只进行过一次交易
3、进行了一次买卖
4、 进行了一次买卖,之后再买入
5、完成了两次交易
*/
// 买入价格初始化到最小, 相当于初始化为第0天
int firstBuy = Integer.MIN_VALUE,first_sell =0;
int secondBuy = Integer.MIN_VALUE,second_Sell = 0;
for(int curPrice:prices){
// 注意买入是负数,卖出是正数
if(firstBuy < -curPrice){
firstBuy = -curPrice; // 买之后的收益为负数
}
if(first_sell < firstBuy+curPrice){ // 每利润的情况,当天卖出后收益变多
first_sell = firstBuy+curPrice;
}
if(secondBuy <first_sell-curPrice){ // 第二次买入
secondBuy = first_sell-curPrice;
}
if(second_Sell <secondBuy+curPrice){ // 第二次卖出
second_Sell = secondBuy+curPrice;
}
}
return second_Sell;
}
}
class Solution {
public int maxProfit(int k, int[] prices) {
// 同样当天的情况只是与前一天有关
if(prices.length ==0) return 0;
int n = prices.length;
// 分成两种情况,如果k大于n/2 ,就当成普通的情况来处理
if(k>= n/2){ //说明说有的都可以进行买卖
int maxProfix =0;
for(int i =1;i<n;++i){
if(prices[i] > prices[i-1]){ // 只要有收益就进行买卖
maxProfix += prices[i] - prices[i-1];
}
}
return maxProfix;
}
// 小于原本内的时候就进行动态规划
int[][] dp = new int[k+1][n]; // k表示第几次交易,n表示第几天
for(int i =1;i<=k;++i){
// 当前手上持有股票,初始情况下第一次交易,想持有,只能以第0天的价格买入
int localMax = dp[i-1][0] - prices[0];
for(int j=1;j<n;++j){
// i 表示第几次交易,j表示第几天
/**
第i比交易后,手上没有股票了,要么是第j-1天手上就已经完成了i比交易不持有了 dp[i][j-1];
要么是i-1 次交易时手上还有股票,第j天卖出去了localMax+prices[j]
*/
dp[i][j] = Math.max(dp[i][j-1],localMax+prices[j]);
/**
第i比交易后,手上还持有一只股票,要么是i-1 次交易后,手上已经持有了,要么是i-1次交易后手上没持有,
第i次以价 格price[j] 买入
*/
localMax = Math.max(localMax,dp[i-1][j] -prices[j]);
}
}
return dp[k][n-1];
}
}
+