动态规划表设置
第一维是第i
天,第二维是目前交易的次数k
,第三维是当前是否持有股票dp[i][k][0]
是不持有股票,dp[i][k][1]
是持有股票
基准情况
1 | dp[-1][k][0] = 0, dp[-1][k][1] = -Infinity |
状态转移方程
1 | dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]) |
1 |
|
dp[i][1][0] = max(dp[i - 1][1][0], dp[i - 1][1][1] + prices[i])
dp[i][1][1] = max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i]) = max(dp[i - 1][1][1], -prices[i])
1 |
|
dp[0][0] = 0;
dp[0][1] = -prices[0];
1 | **状态转移方程** |
dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+price[i])
dp[i][1]=Math.max(dp[i-1][1],-price[i]);
1 |
|
当k为正无穷时,可以任意次交易
如果 k 为正无穷,则 k 和 k - 1 可以看成是相同的
1 | dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]) |
基准情况
1 | dp[0][0] = 0; |
状态转移方程
1 | dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+price[i]) |
1 | class Solution { |
当k=2时,即仅允许交易两次
基准情况
1 | dp[0][1][0] = 0; |
状态转移方程
1 | dp[i][2][0] = max(dp[i - 1][2][0], dp[i - 1][2][1] + prices[i]) |
1 | class Solution { |
当 0<= K <=price.length/2 时
一个有收益的交易至少需要两天(在前一天买入,在后一天卖出,前提是买入价格低于卖出价格)。如果股票价格数组的长度为 n
,则有收益的交易的数量最多为 $n / 2$(整数除法)。因此 k
的临界值是 $n / 2$。如果给定的 k
不小于临界值,即 $k >= n / 2$,则可以将 k
扩展为正无穷,此时问题等价于情况二。
可以写出时间复杂度为 $O(nk)$ 和空间复杂度为 $O(nk)$ 的解法。
1 | class Solution { |
k为正无穷但有冷却时间
但是在有「冷却时间」的情况下,如果在第 i - 1
天卖出了股票,就不能在第 i
天买入股票。因此,如果要在第 i
天买入股票,第二个状态转移方程中就不能使用dp[i - 1][k][0]
,而应该使用 dp[i - 2][k][0]
。状态转移方程中的别的项保持不变,新的状态转移方程如下:
1 | dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]) |
1 | class Solution { |
k为正无穷但有手续费
由于需要对每次交易付手续费,因此在每次买入或卖出股票之后的收益需要扣除手续费,新的状态转移方程有两种表示方法。
第一种表示方法,在每次买入股票时扣除手续费:
1 | dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]) |
1 | class Solution { |
第二种表示方法,在每次卖出股票时扣除手续费:
1 | dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i] - fee) |
1 | class Solution { |
参考文献
1 | 作者:Storm |