LeetCode解题 188:Best Time to Buy and Sell Stock IV (动态规划)
Problem 188: Best Time to Buy and Sell Stock IV [Hard]
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most k transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
Example 1:
Input: [2,4,1], k = 2
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.
Example 2:
Input: [3,2,6,5,0,3], k = 2
Output: 7
Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4.
Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
来源:LeetCode
解题思路
本题需要使用动态规划思想。与题解123:Best Time to Buy and Sell Stock III同属于最佳时机买卖股票问题。
解题思路选用[题解123]中的方法III,123题中是最多可以交易2次,复杂度为
O
(
n
)
O(n)
O(n)时间+
O
(
4
)
O(4)
O(4)空间,本题中最多可以交易k次,所以复杂度为
O
(
n
)
O(n)
O(n)时间+
O
(
2
k
)
O(2k)
O(2k)空间。
在一次循环中,可以使用k组{minCostj, maxPj},先计算第一轮的{minCost1, maxP1},再计算第二轮的{minCost2, maxP2},…,最后计算第k轮的{minCostk, maxPk}。
更新公式为:
c
p
c
p
0
=
[
p
r
i
c
e
s
[
0
]
0
p
r
i
c
e
s
[
0
]
0
.
.
.
p
r
i
c
e
s
[
0
]
0
]
cpcp_0 = \begin{bmatrix} prices[0] \\ 0 \\ prices[0] \\ 0 \\ ... \\ prices[0] \\ 0 \end{bmatrix} \\
cpcp0=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡prices[0]0prices[0]0...prices[0]0⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤
c
p
c
p
=
[
{
min
{
c
p
c
p
[
0
]
,
p
r
i
c
e
s
[
i
]
}
max
{
c
p
c
p
[
1
]
,
p
r
i
c
e
s
[
i
]
−
c
p
c
p
[
0
]
}
.
.
.
min
{
c
p
c
p
[
2
∗
j
]
,
p
r
i
c
e
s
[
i
]
−
c
p
c
p
[
2
∗
j
−
1
]
}
max
{
c
p
c
p
[
2
∗
j
+
1
]
,
p
r
i
c
e
s
[
i
]
−
c
p
c
p
[
2
∗
j
]
}
.
.
.
min
{
c
p
c
p
[
2
∗
k
−
2
]
,
p
r
i
c
e
s
[
i
]
−
c
p
c
p
[
2
∗
k
−
3
]
}
max
{
c
p
c
p
[
2
∗
k
−
1
]
,
p
r
i
c
e
s
[
i
]
−
c
p
c
p
[
2
∗
k
−
2
]
}
]
,
i
∈
[
0
,
N
−
1
]
,
j
∈
[
0
,
k
−
1
]
cpcp = \begin{bmatrix} \{\min\{cpcp[0], prices[i]\} \\ \max\{cpcp[1], prices[i]-cpcp[0]\} \\ ... \\ \min\{cpcp[2*j], prices[i] - cpcp[2*j-1]\} \\ \max\{cpcp[2*j+1], prices[i] - cpcp[2*j]\} \\ ... \\ \min\{cpcp[2*k-2], prices[i] - cpcp[2*k-3]\} \\ \max\{cpcp[2*k-1], prices[i] - cpcp[2*k-2]\} \end{bmatrix}, i\in[0, N-1], j\in[0, k-1]
cpcp=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡{min{cpcp[0],prices[i]}max{cpcp[1],prices[i]−cpcp[0]}...min{cpcp[2∗j],prices[i]−cpcp[2∗j−1]}max{cpcp[2∗j+1],prices[i]−cpcp[2∗j]}...min{cpcp[2∗k−2],prices[i]−cpcp[2∗k−3]}max{cpcp[2∗k−1],prices[i]−cpcp[2∗k−2]}⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤,i∈[0,N−1],j∈[0,k−1]
其中
N
N
N为总天数,
k
k
k为最大交易次数。
c
p
c
p
=
{
m
i
n
C
o
s
t
1
,
m
a
x
P
1
,
.
.
.
,
m
i
n
C
o
s
t
j
+
1
,
m
a
x
P
j
+
1
,
.
.
.
,
m
i
n
C
o
s
t
k
,
m
a
x
P
k
}
cpcp = \{minCost_1, maxP_1, ...,minCost_{j+1}, maxP_{j+1},...,minCost_k, maxP_k\}
cpcp={minCost1,maxP1,...,minCostj+1,maxPj+1,...,minCostk,maxPk},更新过程相当于
c
p
c
p
=
[
m
i
n
C
o
s
t
1
=
min
{
m
i
n
C
o
s
t
1
,
p
r
i
c
e
s
[
i
]
}
m
a
x
P
1
=
max
{
m
a
x
P
1
,
p
r
i
c
e
s
[
i
]
−
m
i
n
C
o
s
t
1
}
.
.
.
m
i
n
C
o
s
t
j
+
1
=
min
{
m
i
n
C
o
s
t
j
+
1
,
p
r
i
c
e
s
[
i
]
−
m
a
x
P
j
}
m
a
x
P
j
+
1
=
max
{
m
a
x
P
j
+
1
,
p
r
i
c
e
s
[
i
]
−
m
i
n
C
o
s
t
j
+
1
}
.
.
.
m
i
n
C
o
s
t
k
=
min
{
m
i
n
C
o
s
t
k
,
p
r
i
c
e
s
[
i
]
−
m
a
x
P
k
−
1
}
m
a
x
P
k
=
max
{
m
a
x
P
k
,
p
r
i
c
e
s
[
i
]
−
m
i
n
C
o
s
t
k
}
]
cpcp = \begin{bmatrix} minCost_1 = \min\{minCost_1,prices[i]\} \\ maxP_1 = \max\{maxP_1,prices[i]-minCost_1\} \\ ... \\ minCost_{j+1} = \min\{minCost_{j+1},prices[i]-maxP_j\} \\ maxP_{j+1} = \max\{maxP_{j+1}, prices[i]-minCost_{j+1}\} \\ ... \\ minCost_k = \min\{minCost_k,prices[i]-maxP_{k-1}\} \\ maxP_k = \max\{maxP_k,prices[i]-minCost_k\} \end{bmatrix}
cpcp=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡minCost1=min{minCost1,prices[i]}maxP1=max{maxP1,prices[i]−minCost1}...minCostj+1=min{minCostj+1,prices[i]−maxPj}maxPj+1=max{maxPj+1,prices[i]−minCostj+1}...minCostk=min{minCostk,prices[i]−maxPk−1}maxPk=max{maxPk,prices[i]−minCostk}⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
该方法只需要
O
(
n
)
O(n)
O(n)时间,
O
(
2
k
)
O(2k)
O(2k)空间。
注意:当k非常大时,会出现超出内存限制的问题,此时需要将 k > N 2 k > \frac{N}{2} k>2N的情况分开考虑。由于一次交易至少需要两天,所以当 k > N 2 k > \frac{N}{2} k>2N时,实际上相当于交易次数不受限制,也就是题解122:Best Time to Buy and Sell Stock II中的题意,可以复用该题的代码。
运行结果:
要点:动态规划
Solution (Java)
O(n)时间+O(2k)空间
class Solution {
public int maxProfit(int k, int[] prices) {
int N = prices.length;
if(k < 1 || N < 2) return 0;
if(k > N/2) return nolimit(prices);
int[] cpcp = new int[2*k];
for(int j = 0; j < k; j++){
cpcp[2*j] = prices[0];
cpcp[2*j+1] = 0;
}
for(int i = 1; i < N; i++){
cpcp[0] = Math.min(cpcp[0], prices[i]);
cpcp[1] = Math.max(cpcp[1], prices[i] - cpcp[0]);
for(int j = 1; j < k; j++){
cpcp[2*j] = Math.min(cpcp[2*j], prices[i] - cpcp[2*j-1]);
cpcp[2*j+1] = Math.max(cpcp[2*j+1], prices[i] - cpcp[2*j]);
}
}
return cpcp[2*k-1];
}
private int nolimit(int[] prices){
int maxP = 0;
for(int i = 1; i < prices.length; i++){
maxP += Math.max(0, prices[i] - prices[i-1]);
}
return maxP;
}
}
修改过程
- 样例输入k=1000000000时,出现超出内存限制问题,需要将其考虑为无限次交易的情况,因此添加函数nolimit()。