一.leetcode 121:给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

分析:

1.最多只允许完成一笔交易,低价买,高价卖

2.第i天的时候,手里要么有股票,要么没有股票,只会有这两种情况;有股票:昨天就有了,今天不用操作;昨天没有,今天买。没有股票:昨天就没有了,今天不操作;昨天有,今天卖。

3.第i天要想获取最大利润,手里肯定是没有股票的情况,因为股票不可能是负值

4.用prices[i]数组表示第i天时,股票的价格

用dp1数组存储第i天,持有股票的最大利润,则dp1[i] = Math.max(dp1[i - 1], -prices[i]);//dp1[i-1]表示第i-1天就持有股票了,-prices[i]表示之前没有股票,第i天买股票

dp2数组存储第i天,不持有股票的最大利润,则dp2[i] = Math.max(dp2[i - 1], prices[i] + dp1[i-1]);//dp2[i-1]表示第i-1天就不持有股票了,prices[i] + dp1[i-1]表示第i-1天持有股票,第i天卖股票;概述如下:

第i天有股票:
昨天就持股了,今天不操作;
之前没有买过,今天买;

第i天没有股票:
昨天就没有持股,今天不操作;
昨天持股,今天卖

......

有了递推方程和初始状态值dp1[0] =-prices[0];dp2[0] = 0;层层递推

代码部分

 1 public static int maxProfit(int[] prices) {
 2         if (prices.length == 0 || prices.length == 1) {
 3             return 0;
 4         }
 5         // dp1数组存储第`i`天,持有股票的最大利润
 6         int[] dp1 = new int[prices.length];
 7         dp1[0] = -prices[0];
 8         // dp2数组存储第`i`天,不持有股票的最大利润
 9         int[] dp2 = new int[prices.length];
10         dp2[0] = 0;
11 
12         for (int i = 1; i < prices.length; i++) {
13             dp1[i] = Math.max(dp1[i - 1], -prices[i]);//前一天就有,今天不操作;前一天没有,今天买
14             dp2[i] = Math.max(dp2[i - 1], prices[i] + dp1[i - 1]);//前一天就没有,今天不操作;前一天有,今天卖
15         }
16         int maxProfit = dp2[dp2.length - 1];
17         System.out.println("最大利润:"+maxProfit);
18         return maxProfit;
19     }
java

二.leetcode 122:你可以尽可能地完成更多的交易(多次买卖一支股票)
思路和上面一完全一样,唯一的区别就是:昨天没有股票,今天有股票了,对于一,之前肯定没有买过股票,即-prices[i];而不限制买卖次数后,可能是之前买过,但昨天卖了或者之前卖了,现在再买

dp1[i] = Math.max(dp1[i - 1], dp2[i-1]-prices[i]);//前一天就持股,今天不操作;昨天没有(之前可能买卖过),今天买
dp2[i] = Math.max(dp2[i - 1], prices[i] + dp1[i - 1]);//前一天就没有持股,今天不操作;昨天有持股,今天卖

概述如下:
第i天有股票:
昨天就持股了,今天不操作;
昨天没有持股(之前可能买卖过),今天买;

第i天没有股票:
昨天就没有持股,今天不操作;
昨天持股,今天卖

三.leetcode 714:每次卖股票的时候要减手续费fee(非负数)
1.对于上面一

dp1[i] = Math.max(dp1[i - 1], -prices[i]);//第i天持股
dp2[i] = Math.max(dp2[i - 1], prices[i] + dp1[i - 1] - fee);//第i天没有持股,卖股票的时候要减手续费

2.对于上面二

dp1[i] = Math.max(dp1[i - 1], dp2[i-1]-prices[i]);//第i天持股
dp2[i] = Math.max(dp2[i - 1], prices[i] + dp1[i - 1] - fee);//第i天没有持股,卖股票的时候要减手续费

四.含冷冻期

卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)

第i天有股票:
可能是昨天就持股了,今天不操作,和上面二,三一样;
昨天没有持股,今天要买股票;如果昨天卖过股票的话,有一天的冷冻期,所以今天能买股票的前置条件是昨天没买也没卖过股票;这个条件一维数组表达不出来,增加一维,0表示本不持有,1表示持有,2表示当天卖出
第i天没有股票:
昨天就没有持股,今天不操作;
昨天有持股,今天卖,和上面二、三一样

dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]); //今天本不持有:昨天本不持有或昨天卖出
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); //今天持有:昨天就持有或昨天本不持有-今天买进一只股票
dp[i][2] = dp[i - 1][1] + prices[i]; //当天卖出:昨天持有+当天的股票价格

代码部分

 1 int len = prices.length;
 2         if (len < 2) return 0;
 3         //0表示本不持有,1表示持有,2表示当天卖出,不持有
 4         int[][] dp = new int[len][3];  //用二维数组记录当天各种情况的最优解(收益的最大值)
 5         dp[0][1] = -prices[0];  //第一天若持有,则收益为负;不持有则收益为零
 6 
 7         for (int i = 1; i < len; i++){
 8             dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]);  //当天的本不持有可以由前一天本不持有或前一天卖出得到
 9             dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);  //当天的持有可以由前一天的持有或前一天的本不持有-当天的股票价格得到, 即买进一只股票
10             dp[i][2] = dp[i - 1][1] + prices[i];  //当天卖出可以由前一天的持有+当天的股票价格得到, 即卖出手中的股票
11         }
12         return Math.max(dp[len - 1][0], dp[len - 1][2]);  //返回最后一天不持有股票的状态,此处可以得到收益的最大值
java

回过头来看一下,其实一、二、三用了两个一维数组,dp1当天持股的数组、dp2当天不持股的数组,其实可以用四中的二维数组替换掉





dp1