继续每日一题,今天给大家分享一道经典的多维动态规划题目:买卖股票的最佳时机II
题目描述:
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
题目示例:
对于动态规划类的题目,无论是一维还是多维,我们的目的都是找到一个合适的状态转移方程来满足无后效性,对于本题,我们除了要标记收益之外还需要知道当前收益下的持股状态,所以我们声明dp数组:dp[i][j],表示:
下标为 i 的这一天,持股状态为 j 时,我们手上拥有的最大现金数。
j有两种状态:股票(1) or 现金(0)
- dp[i][0]:表示在第i天持有现金的最大收益
- dp[i][1]:表示第i天持有股票的最大收益
所以我们的公式如下;
d
p
[
i
]
[
j
]
=
{
M
a
t
h
.
m
a
x
(
d
p
[
i
−
1
]
[
0
]
,
d
p
[
i
−
1
]
[
1
]
+
p
r
i
c
e
[
i
]
)
,
j
=
=
0
M
a
t
h
.
m
a
x
(
d
p
[
i
−
1
]
[
1
]
,
d
p
[
i
−
1
]
[
0
]
−
p
r
i
c
e
[
i
]
)
,
j
=
=
1
dp[i][j]= \begin{cases} Math.max(dp[i-1][0],dp[i-1][1]+price[i]), & \text{ $j==0$ } \\ Math.max(dp[i-1][1],dp[i-1][0]-price[i]), & \text{ $j==1$ } \end{cases}
dp[i][j]={Math.max(dp[i−1][0],dp[i−1][1]+price[i]),Math.max(dp[i−1][1],dp[i−1][0]−price[i]), j==0 j==1
我来给大家解释一下每状态下的公式含义
- dp[i][0]即当天持有的是现金的情况,这种情况需要我们在当天卖出股票换成钱
如果前一天持有的也是现金即dp[i-1][0],那么当天就无可卖出的股票,所以收益和前一天是一样的
如果前一天持有的是股票即dp[i-1][1],那么当天就有可卖出的股票,卖出的钱就是price[i],所以当天的收益为:p[i-1][1]+price[i]
- dp[i][1]即当天持有的是股票的情况,这种情况需要我们买入股票
如果前一天持有的是股票即dp[i-1][1],因为题目要求无论在任何时候都只能有一支股票,所以当天就无法买入,收益和前一天一样
如果前一天持有的是现金即dp[i-1][0],那么当天就有可以买入股票,买入的价格则是price[i],此时我们的收益就需要减去买股票的钱,即:p[i-1][0]-price[i]
了解上面内容后,我们还有最后一点待定,就是初始值,在动态规划的题目中,我们的步骤就是确定动态转移方程以满足无后效性问题,第二步则是确定初始值
- dp[0][0],第一天持有现金,则无任何收益,故:dp[0][0]=0;
- dp[0][1],第一天持有股票,则需要买入,买入的价格为:price[0],故:dp[0][1]=0-price[0]
代码实现(java):
public int maxProfit(int[] prices) {
int n = prices.length;
int[][] dp = new int[n][2];
//0:持有现金 1:持有股票
dp[0][0] = 0;
dp[0][1] = 0 - prices[0];
for (int i = 1; i < n; 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 Math.max(dp[n - 1][0], dp[n - 1][1]);
}