地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
我写的题解地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/tan-xin-suan-fa-by-liweiwei1419-2/
方法一:动态规划
定义状态: dp[i][j]
说明:第一维 i
表示区间 [0, i]
(具有前缀性质,即考虑了之前天数的收益)能获得的最大利润;
第二维 j
表示索引位置为 i
的那一天我是持有股票,还是持有现金,这里 0
表示持有现金(cash),1
表示持有股票(stock)。
- 状态转移方程:
状态从持有现金(cash)开始,到最后一天我们关心的状态也是持有现金(cash),因为股价是正数,最后一天买进一支股票,手上的现金肯定少了;
每一天状态可以转移,也可以不动。 可以用下图表示:
因此状态转移方程是:
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]);
-
初始化:起始的时候,不持有股票。如果什么都不做,
dp[0][0] = 0
,如果买入股票,当前收益是负数,即dp[0][1] = -prices[i];
-
输出:
dp[len - 1][0]
。因为不限制交易次数,也没有冷冻期,因此最后一天一定得把手上持有的股票卖掉,即一定有dp[len - 1][0] > dp[len - 1][1]
。
Java 代码:
public class Solution {
// 0:持有现金
// 1:持有股票
public int maxProfit(int[] prices) {
int len = prices.length;
if (len < 2) {
return 0;
}
// 状态数组
// 状态转移:cash → hold → cash → hold → cash → hold → cash
// 状态转移:0 → 1 → 0 → 1 → 0 → 1 → 0
int[][] dp = new int[len][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < len; i++) {
// 说明这两行调换顺序也是可以的
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[len - 1][0];
}
}
还可以这样写:
Java 代码:
public class Solution {
// cash:持有现金
// hold:持有股票
public int maxProfit(int[] prices) {
int len = prices.length;
if (len < 2) {
return 0;
}
// 状态数组
// 状态转移:cash → hold → cash → hold → cash → hold → cash
int[] cash = new int[len];
int[] hold = new int[len];
cash[0] = 0;
hold[0] = -prices[0];
for (int i = 1; i < len; i++) {
// 说明这两行调换顺序也是可以的
cash[i] = Math.max(cash[i - 1], hold[i - 1] + prices[i]);
hold[i] = Math.max(hold[i - 1], cash[i - 1] - prices[i]);
}
return cash[len - 1];
}
}
状态压缩(如果是刚开始接触,可以跳过,我个人觉得不是很重要,重点理解状态转移)
Java 代码:
public class Solution {
// cash:持有现金
// hold:持有股票
public int maxProfit(int[] prices) {
int len = prices.length;
if (len < 2) {
return 0;
}
// 状态数组
// 状态转移:cash → hold → cash → hold → cash → hold → cash
int cash = 0;
int hold = -prices[0];
int preCash = cash;
int preHold = hold;
for (int i = 1; i < len; i++) {
cash = Math.max(preCash, preHold + prices[i]);
hold = Math.max(preHold, preCash - prices[i]);
preCash = cash;
preHold = hold;
}
return cash;
}
}
方法二:贪心算法
贪心算法的证明见本文开始贴出的我的题解地址。
Java 代码:
public class Solution {
public int maxProfit(int[] prices) {
int res = 0;
int len = prices.length;
for (int i = 0; i < len - 1; i++) {
int diff = prices[i + 1] - prices[i];
if (diff > 0) {
res += diff;
}
}
return res;
}
}