Skip to content

Commit 9f04133

Browse files
authored
feat: add solutions to lc problem: No.0309 (#1744)
No.0309.Best Time to Buy and Sell Stock with Cooldown
1 parent 58746c7 commit 9f04133

File tree

7 files changed

+539
-139
lines changed

7 files changed

+539
-139
lines changed

solution/0300-0399/0309.Best Time to Buy and Sell Stock with Cooldown/README.md

+262-50
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,33 @@
4545

4646
<!-- 这里可写通用的实现逻辑 -->
4747

48-
动态规划法。
48+
**方法一:记忆化搜索**
4949

50-
设 f1 表示当天买入股票后的最大利润,f2 表示当天卖出股票后的最大利润,f3 表示当天空仓后的最大利润
50+
我们设计一个函数 $dfs(i, j)$,表示从第 $i$ 天开始,状态为 $j$ 时,能够获得的最大利润。其中 $j$ 的取值为 $0, 1$,分别表示当前不持有股票和持有股票。答案即为 $dfs(0, 0)$
5151

52-
初始第 1 天结束时,`f1 = -prices[0]``f2 = 0``f3 = 0`
52+
函数 $dfs(i, j)$ 的执行逻辑如下:
5353

54-
从第 2 天开始,当天结束时:
54+
如果 $i \geq n$,表示已经没有股票可以交易了,此时返回 $0$;
5555

56-
- 若买入,则说明前一天空仓,然后今天买入,`f1 = max(f1, f3 - prices[i])`
57-
- 若卖出,则只能是之前某一天买入,然后今天卖出,`f2 = max(f2, f1 + prices[i])`
58-
- 若空仓,则只能是之前某一天卖出后,然后今天保持空仓,`f3 = max(f3, f2)`
56+
否则,我们可以选择不交易,此时 $dfs(i, j) = dfs(i + 1, j)$。我们也可以进行股票交易,如果此时 $j \gt 0$,说明当前持有股票,可以卖出,此时 $dfs(i, j) = prices[i] + dfs(i + 2, 0)$;如果此时 $j = 0$,说明当前不持有股票,可以买入,此时 $dfs(i, j) = -prices[i] + dfs(i + 1, 1)$。取最大值作为函数 $dfs(i, j)$ 的返回值。
5957

60-
最后返回 f2 即可。
58+
答案为 $dfs(0, 0)$。
59+
60+
为了避免重复计算,我们使用记忆化搜索的方法,用一个数组 $f$ 记录 $dfs(i, j)$ 的返回值,如果 $f[i][j]$ 不为 $-1$,说明已经计算过,直接返回 $f[i][j]$ 即可。
61+
62+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $prices$ 的长度。
63+
64+
**方法二:动态规划**
65+
66+
我们也可以用动态规划的方法求解。
67+
68+
我们定义 $f[i][j]$ 表示到第 $i$ 天,且状态为 $j$ 时,能够获得的最大利润。其中 $j$ 的取值为 $0, 1$,分别表示当前不持有股票和持有股票。初始时 $f[0][0] = 0$, $f[0][1] = -prices[0]$。
69+
70+
当 $i \geq 1$ 时,如果当前不持有股票,那么 $f[i][0]$ 可以由 $f[i - 1][0]$ 和 $f[i - 1][1] + prices[i]$ 转移得到,即 $f[i][0] = \max(f[i - 1][0], f[i - 1][1] + prices[i])$;如果当前持有股票,那么 $f[i][1]$ 可以由 $f[i - 1][1]$ 和 $f[i - 2][0] - prices[i]$ 转移得到,即 $f[i][1] = \max(f[i - 1][1], f[i - 2][0] - prices[i])$。最终答案为 $f[n - 1][0]$。
71+
72+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $prices$ 的长度。
73+
74+
我们注意到,状态 $f[i][]$ 的转移只与 $f[i - 1][]$ 和 $f[i - 2][0]$ 有关,因此我们可以用三个变量 $f, f_0, f_1$ 代替数组 $f$,将空间复杂度优化到 $O(1)$。
6175

6276
<!-- tabs:start -->
6377

@@ -68,14 +82,39 @@
6882
```python
6983
class Solution:
7084
def maxProfit(self, prices: List[int]) -> int:
71-
# 买入,卖出,继续空仓
72-
f1, f2, f3 = -prices[0], 0, 0
73-
for price in prices[1:]:
74-
pf1, pf2, pf3 = f1, f2, f3
75-
f1 = max(pf1, pf3 - price)
76-
f2 = max(pf2, pf1 + price)
77-
f3 = max(pf3, pf2)
78-
return f2
85+
@cache
86+
def dfs(i: int, j: int) -> int:
87+
if i >= len(prices):
88+
return 0
89+
ans = dfs(i + 1, j)
90+
if j:
91+
ans = max(ans, prices[i] + dfs(i + 2, 0))
92+
else:
93+
ans = max(ans, -prices[i] + dfs(i + 1, 1))
94+
return ans
95+
96+
return dfs(0, 0)
97+
```
98+
99+
```python
100+
class Solution:
101+
def maxProfit(self, prices: List[int]) -> int:
102+
n = len(prices)
103+
f = [[0] * 2 for _ in range(n)]
104+
f[0][1] = -prices[0]
105+
for i in range(1, n):
106+
f[i][0] = max(f[i - 1][0], f[i - 1][1] + prices[i])
107+
f[i][1] = max(f[i - 1][1], f[i - 2][0] - prices[i])
108+
return f[n - 1][0]
109+
```
110+
111+
```python
112+
class Solution:
113+
def maxProfit(self, prices: List[int]) -> int:
114+
f, f0, f1 = 0, 0, -prices[0]
115+
for x in prices[1:]:
116+
f, f0, f1 = f0, max(f0, f1 + x), max(f1, f - x)
117+
return f0
79118
```
80119

81120
### **Java**
@@ -84,35 +123,60 @@ class Solution:
84123

85124
```java
86125
class Solution {
126+
private int[] prices;
127+
private Integer[][] f;
128+
87129
public int maxProfit(int[] prices) {
88-
// 买入,卖出,继续空仓
89-
int f1 = -prices[0], f2 = 0, f3 = 0;
90-
for (int i = 1; i < prices.length; ++i) {
91-
int pf1 = f1, pf2 = f2, pf3 = f3;
92-
f1 = Math.max(pf1, pf3 - prices[i]);
93-
f2 = Math.max(pf2, pf1 + prices[i]);
94-
f3 = Math.max(pf3, pf2);
130+
this.prices = prices;
131+
f = new Integer[prices.length][2];
132+
return dfs(0, 0);
133+
}
134+
135+
private int dfs(int i, int j) {
136+
if (i >= prices.length) {
137+
return 0;
138+
}
139+
if (f[i][j] != null) {
140+
return f[i][j];
141+
}
142+
int ans = dfs(i + 1, j);
143+
if (j > 0) {
144+
ans = Math.max(ans, prices[i] + dfs(i + 2, 0));
145+
} else {
146+
ans = Math.max(ans, -prices[i] + dfs(i + 1, 1));
95147
}
96-
return f2;
148+
return f[i][j] = ans;
97149
}
98150
}
99151
```
100152

101-
### **TypeScript**
153+
```java
154+
class Solution {
155+
public int maxProfit(int[] prices) {
156+
int n = prices.length;
157+
int[][] f = new int[n][2];
158+
f[0][1] = -prices[0];
159+
for (int i = 1; i < n; i++) {
160+
f[i][0] = Math.max(f[i - 1][0], f[i - 1][1] + prices[i]);
161+
f[i][1] = Math.max(f[i - 1][1], (i > 1 ? f[i - 2][0] : 0) - prices[i]);
162+
}
163+
return f[n - 1][0];
164+
}
165+
}
166+
```
102167

103-
```ts
104-
function maxProfit(prices: number[]): number {
105-
const n = prices.length;
106-
let dp = Array.from({ length: n }, v => new Array(3).fill(0));
107-
dp[0] = [0, -prices[0], Number.MIN_SAFE_INTEGER];
108-
for (let i = 1; i < n; i++) {
109-
dp[i] = [
110-
Math.max(dp[i - 1][0], dp[i - 1][2]),
111-
Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]),
112-
dp[i - 1][1] + prices[i],
113-
];
168+
```java
169+
class Solution {
170+
public int maxProfit(int[] prices) {
171+
int f = 0, f0 = 0, f1 = -prices[0];
172+
for (int i = 1; i < prices.length; ++i) {
173+
int g0 = Math.max(f0, f1 + prices[i]);
174+
f1 = Math.max(f1, f - prices[i]);
175+
f = f0;
176+
f0 = g0;
177+
}
178+
return f0;
114179
}
115-
return Math.max(dp[n - 1][0], dp[n - 1][2]);
116180
}
117181
```
118182

@@ -122,14 +186,58 @@ function maxProfit(prices: number[]): number {
122186
class Solution {
123187
public:
124188
int maxProfit(vector<int>& prices) {
125-
int f1 = -prices[0], f2 = 0, f3 = 0;
189+
int n = prices.size();
190+
int f[n][2];
191+
memset(f, -1, sizeof(f));
192+
function<int(int, int)> dfs = [&](int i, int j) {
193+
if (i >= n) {
194+
return 0;
195+
}
196+
if (f[i][j] != -1) {
197+
return f[i][j];
198+
}
199+
int ans = dfs(i + 1, j);
200+
if (j) {
201+
ans = max(ans, prices[i] + dfs(i + 2, 0));
202+
} else {
203+
ans = max(ans, -prices[i] + dfs(i + 1, 1));
204+
}
205+
return f[i][j] = ans;
206+
};
207+
return dfs(0, 0);
208+
}
209+
};
210+
```
211+
212+
```cpp
213+
class Solution {
214+
public:
215+
int maxProfit(vector<int>& prices) {
216+
int n = prices.size();
217+
int f[n][2];
218+
memset(f, 0, sizeof(f));
219+
f[0][1] = -prices[0];
220+
for (int i = 1; i < n; ++i) {
221+
f[i][0] = max(f[i - 1][0], f[i - 1][1] + prices[i]);
222+
f[i][1] = max(f[i - 1][1], (i > 1 ? f[i - 2][0] : 0) - prices[i]);
223+
}
224+
return f[n - 1][0];
225+
}
226+
};
227+
```
228+
229+
```cpp
230+
class Solution {
231+
public:
232+
int maxProfit(vector<int>& prices) {
233+
int f = 0, f0 = 0, f1 = -prices[0];
126234
for (int i = 1; i < prices.size(); ++i) {
127-
int pf1 = f1, pf2 = f2, pf3 = f3;
128-
f1 = max(pf1, pf3 - prices[i]);
129-
f2 = max(pf2, pf1 + prices[i]);
130-
f3 = max(pf3, pf2);
235+
int g0 = max(f0, f1 + prices[i]);
236+
f1 = max(f1, f - prices[i]);
237+
f = f0;
238+
f0 = g0;
131239
}
132-
return f2;
240+
return f0;
133241
}
134242
};
135243
```
@@ -138,14 +246,70 @@ public:
138246
139247
```go
140248
func maxProfit(prices []int) int {
141-
f1, f2, f3 := -prices[0], 0, 0
142-
for i := 1; i < len(prices); i++ {
143-
pf1, pf2, pf3 := f1, f2, f3
144-
f1 = max(pf1, pf3-prices[i])
145-
f2 = max(pf2, pf1+prices[i])
146-
f3 = max(pf3, pf2)
249+
n := len(prices)
250+
f := make([][2]int, n)
251+
for i := range f {
252+
f[i] = [2]int{-1, -1}
253+
}
254+
var dfs func(i, j int) int
255+
dfs = func(i, j int) int {
256+
if i >= n {
257+
return 0
258+
}
259+
if f[i][j] != -1 {
260+
return f[i][j]
261+
}
262+
ans := dfs(i+1, j)
263+
if j > 0 {
264+
ans = max(ans, prices[i]+dfs(i+2, 0))
265+
} else {
266+
ans = max(ans, -prices[i]+dfs(i+1, 1))
267+
}
268+
f[i][j] = ans
269+
return ans
270+
}
271+
return dfs(0, 0)
272+
}
273+
274+
func max(a, b int) int {
275+
if a > b {
276+
return a
277+
}
278+
return b
279+
}
280+
```
281+
282+
```go
283+
func maxProfit(prices []int) int {
284+
n := len(prices)
285+
f := make([][2]int, n)
286+
f[0][1] = -prices[0]
287+
for i := 1; i < n; i++ {
288+
f[i][0] = max(f[i-1][0], f[i-1][1]+prices[i])
289+
if i > 1 {
290+
f[i][1] = max(f[i-1][1], f[i-2][0]-prices[i])
291+
} else {
292+
f[i][1] = max(f[i-1][1], -prices[i])
293+
}
294+
}
295+
return f[n-1][0]
296+
}
297+
298+
func max(a, b int) int {
299+
if a > b {
300+
return a
301+
}
302+
return b
303+
}
304+
```
305+
306+
```go
307+
func maxProfit(prices []int) int {
308+
f, f0, f1 := 0, 0, -prices[0]
309+
for _, x := range prices[1:] {
310+
f, f0, f1 = f0, max(f0, f1+x), max(f1, f-x)
147311
}
148-
return f2
312+
return f0
149313
}
150314

151315
func max(a, b int) int {
@@ -156,6 +320,54 @@ func max(a, b int) int {
156320
}
157321
```
158322

323+
### **TypeScript**
324+
325+
```ts
326+
function maxProfit(prices: number[]): number {
327+
const n = prices.length;
328+
const f: number[][] = Array.from({ length: n }, () => Array.from({ length: 2 }, () => -1));
329+
const dfs = (i: number, j: number): number => {
330+
if (i >= n) {
331+
return 0;
332+
}
333+
if (f[i][j] !== -1) {
334+
return f[i][j];
335+
}
336+
let ans = dfs(i + 1, j);
337+
if (j) {
338+
ans = Math.max(ans, prices[i] + dfs(i + 2, 0));
339+
} else {
340+
ans = Math.max(ans, -prices[i] + dfs(i + 1, 1));
341+
}
342+
return (f[i][j] = ans);
343+
};
344+
return dfs(0, 0);
345+
}
346+
```
347+
348+
```ts
349+
function maxProfit(prices: number[]): number {
350+
const n = prices.length;
351+
const f: number[][] = Array.from({ length: n }, () => Array.from({ length: 2 }, () => 0));
352+
f[0][1] = -prices[0];
353+
for (let i = 1; i < n; ++i) {
354+
f[i][0] = Math.max(f[i - 1][0], f[i - 1][1] + prices[i]);
355+
f[i][1] = Math.max(f[i - 1][1], (i > 1 ? f[i - 2][0] : 0) - prices[i]);
356+
}
357+
return f[n - 1][0];
358+
}
359+
```
360+
361+
```ts
362+
function maxProfit(prices: number[]): number {
363+
let [f, f0, f1] = [0, 0, -prices[0]];
364+
for (const x of prices.slice(1)) {
365+
[f, f0, f1] = [f0, Math.max(f0, f1 + x), Math.max(f1, f - x)];
366+
}
367+
return f0;
368+
}
369+
```
370+
159371
### **...**
160372

161373
```

0 commit comments

Comments
 (0)