Expand Up
@@ -45,19 +45,33 @@
<!-- 这里可写通用的实现逻辑 -->
动态规划法。
**方法一:记忆化搜索**
设 f1 表示当天买入股票后的最大利润,f2 表示当天卖出股票后的最大利润,f3 表示当天空仓后的最大利润 。
我们设计一个函数 $dfs(i, j),ドル表示从第 $i$ 天开始,状态为 $j$ 时,能够获得的最大利润。其中 $j$ 的取值为 0,ドル 1,ドル分别表示当前不持有股票和持有股票。答案即为 $dfs(0, 0)$ 。
初始第 1 天结束时,`f1 = -prices[0]`,`f2 = 0`,`f3 = 0`。
函数 $dfs(i, j)$ 的执行逻辑如下:
从第 2 天开始,当天结束时:
如果 $i \geq n,ドル表示已经没有股票可以交易了,此时返回 0ドル$;
- 若买入,则说明前一天空仓,然后今天买入,`f1 = max(f1, f3 - prices[i])`。
- 若卖出,则只能是之前某一天买入,然后今天卖出,`f2 = max(f2, f1 + prices[i])`。
- 若空仓,则只能是之前某一天卖出后,然后今天保持空仓,`f3 = max(f3, f2)`。
否则,我们可以选择不交易,此时 $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)$ 的返回值。
最后返回 f2 即可。
答案为 $dfs(0, 0)$。
为了避免重复计算,我们使用记忆化搜索的方法,用一个数组 $f$ 记录 $dfs(i, j)$ 的返回值,如果 $f[i][j]$ 不为 $-1,ドル说明已经计算过,直接返回 $f[i][j]$ 即可。
时间复杂度 $O(n),ドル空间复杂度 $O(n)$。其中 $n$ 为数组 $prices$ 的长度。
**方法二:动态规划**
我们也可以用动态规划的方法求解。
我们定义 $f[i][j]$ 表示到第 $i$ 天,且状态为 $j$ 时,能够获得的最大利润。其中 $j$ 的取值为 0,ドル 1,ドル分别表示当前不持有股票和持有股票。初始时 $f[0][0] = 0,ドル $f[0][1] = -prices[0]$。
当 $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]$。
时间复杂度 $O(n),ドル空间复杂度 $O(n)$。其中 $n$ 为数组 $prices$ 的长度。
我们注意到,状态 $f[i][]$ 的转移只与 $f[i - 1][]$ 和 $f[i - 2][0]$ 有关,因此我们可以用三个变量 $f, f_0, f_1$ 代替数组 $f,ドル将空间复杂度优化到 $O(1)$。
<!-- tabs:start -->
Expand All
@@ -68,14 +82,39 @@
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
# 买入,卖出,继续空仓
f1, f2, f3 = -prices[0], 0, 0
for price in prices[1:]:
pf1, pf2, pf3 = f1, f2, f3
f1 = max(pf1, pf3 - price)
f2 = max(pf2, pf1 + price)
f3 = max(pf3, pf2)
return f2
@cache
def dfs(i: int, j: int) -> int:
if i >= len(prices):
return 0
ans = dfs(i + 1, j)
if j:
ans = max(ans, prices[i] + dfs(i + 2, 0))
else:
ans = max(ans, -prices[i] + dfs(i + 1, 1))
return ans
return dfs(0, 0)
```
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
f = [[0] * 2 for _ in range(n)]
f[0][1] = -prices[0]
for i in range(1, n):
f[i][0] = max(f[i - 1][0], f[i - 1][1] + prices[i])
f[i][1] = max(f[i - 1][1], f[i - 2][0] - prices[i])
return f[n - 1][0]
```
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
f, f0, f1 = 0, 0, -prices[0]
for x in prices[1:]:
f, f0, f1 = f0, max(f0, f1 + x), max(f1, f - x)
return f0
```
### **Java**
Expand All
@@ -84,35 +123,60 @@ class Solution:
```java
class Solution {
private int[] prices;
private Integer[][] f;
public int maxProfit(int[] prices) {
// 买入,卖出,继续空仓
int f1 = -prices[0], f2 = 0, f3 = 0;
for (int i = 1; i < prices.length; ++i) {
int pf1 = f1, pf2 = f2, pf3 = f3;
f1 = Math.max(pf1, pf3 - prices[i]);
f2 = Math.max(pf2, pf1 + prices[i]);
f3 = Math.max(pf3, pf2);
this.prices = prices;
f = new Integer[prices.length][2];
return dfs(0, 0);
}
private int dfs(int i, int j) {
if (i >= prices.length) {
return 0;
}
if (f[i][j] != null) {
return f[i][j];
}
int ans = dfs(i + 1, j);
if (j > 0) {
ans = Math.max(ans, prices[i] + dfs(i + 2, 0));
} else {
ans = Math.max(ans, -prices[i] + dfs(i + 1, 1));
}
return f2 ;
return f[i][j] = ans ;
}
}
```
### **TypeScript**
```java
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
int[][] f = new int[n][2];
f[0][1] = -prices[0];
for (int i = 1; i < n; i++) {
f[i][0] = Math.max(f[i - 1][0], f[i - 1][1] + prices[i]);
f[i][1] = Math.max(f[i - 1][1], (i > 1 ? f[i - 2][0] : 0) - prices[i]);
}
return f[n - 1][0];
}
}
```
```ts
function maxProfit(prices: number[]): number {
const n = prices.length;
let dp = Array.from({ length: n }, v => new Array(3).fill(0)) ;
dp[0] = [0, -prices[0], Number.MIN_SAFE_INTEGER];
for (let i = 1; i < n; i++) {
dp[i] = [
Math.max(dp[i - 1][0], dp[i - 1][2]),
Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]),
dp[i - 1][1] + prices[i],
] ;
```java
class Solution {
public int maxProfit(int[] prices) {
int f = 0, f0 = 0, f1 = -prices[0] ;
for (int i = 1; i < prices.length; ++i) {
int g0 = Math.max(f0, f1 + prices[i]);
f1 = Math.max(f1, f - prices[i]);
f = f0;
f0 = g0;
}
return f0 ;
}
return Math.max(dp[n - 1][0], dp[n - 1][2]);
}
```
Expand All
@@ -122,14 +186,58 @@ function maxProfit(prices: number[]): number {
class Solution {
public:
int maxProfit(vector<int>& prices) {
int f1 = -prices[0], f2 = 0, f3 = 0;
int n = prices.size();
int f[n][2];
memset(f, -1, sizeof(f));
function<int(int, int)> dfs = [&](int i, int j) {
if (i >= n) {
return 0;
}
if (f[i][j] != -1) {
return f[i][j];
}
int ans = dfs(i + 1, j);
if (j) {
ans = max(ans, prices[i] + dfs(i + 2, 0));
} else {
ans = max(ans, -prices[i] + dfs(i + 1, 1));
}
return f[i][j] = ans;
};
return dfs(0, 0);
}
};
```
```cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
int f[n][2];
memset(f, 0, sizeof(f));
f[0][1] = -prices[0];
for (int i = 1; i < n; ++i) {
f[i][0] = max(f[i - 1][0], f[i - 1][1] + prices[i]);
f[i][1] = max(f[i - 1][1], (i > 1 ? f[i - 2][0] : 0) - prices[i]);
}
return f[n - 1][0];
}
};
```
```cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int f = 0, f0 = 0, f1 = -prices[0];
for (int i = 1; i < prices.size(); ++i) {
int pf1 = f1, pf2 = f2, pf3 = f3 ;
f1 = max(pf1, pf3 - prices[i]);
f2 = max(pf2, pf1 + prices[i]) ;
f3 = max(pf3, pf2) ;
int g0 = max(f0, f1 + prices[i]) ;
f1 = max(f1, f - prices[i]);
f = f0 ;
f0 = g0 ;
}
return f2 ;
return f0 ;
}
};
```
Expand All
@@ -138,14 +246,70 @@ public:
```go
func maxProfit(prices []int) int {
f1, f2, f3 := -prices[0], 0, 0
for i := 1; i < len(prices); i++ {
pf1, pf2, pf3 := f1, f2, f3
f1 = max(pf1, pf3-prices[i])
f2 = max(pf2, pf1+prices[i])
f3 = max(pf3, pf2)
n := len(prices)
f := make([][2]int, n)
for i := range f {
f[i] = [2]int{-1, -1}
}
var dfs func(i, j int) int
dfs = func(i, j int) int {
if i >= n {
return 0
}
if f[i][j] != -1 {
return f[i][j]
}
ans := dfs(i+1, j)
if j > 0 {
ans = max(ans, prices[i]+dfs(i+2, 0))
} else {
ans = max(ans, -prices[i]+dfs(i+1, 1))
}
f[i][j] = ans
return ans
}
return dfs(0, 0)
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
```
```go
func maxProfit(prices []int) int {
n := len(prices)
f := make([][2]int, n)
f[0][1] = -prices[0]
for i := 1; i < n; i++ {
f[i][0] = max(f[i-1][0], f[i-1][1]+prices[i])
if i > 1 {
f[i][1] = max(f[i-1][1], f[i-2][0]-prices[i])
} else {
f[i][1] = max(f[i-1][1], -prices[i])
}
}
return f[n-1][0]
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
```
```go
func maxProfit(prices []int) int {
f, f0, f1 := 0, 0, -prices[0]
for _, x := range prices[1:] {
f, f0, f1 = f0, max(f0, f1+x), max(f1, f-x)
}
return f2
return f0
}
func max(a, b int) int {
Expand All
@@ -156,6 +320,54 @@ func max(a, b int) int {
}
```
### **TypeScript**
```ts
function maxProfit(prices: number[]): number {
const n = prices.length;
const f: number[][] = Array.from({ length: n }, () => Array.from({ length: 2 }, () => -1));
const dfs = (i: number, j: number): number => {
if (i >= n) {
return 0;
}
if (f[i][j] !== -1) {
return f[i][j];
}
let ans = dfs(i + 1, j);
if (j) {
ans = Math.max(ans, prices[i] + dfs(i + 2, 0));
} else {
ans = Math.max(ans, -prices[i] + dfs(i + 1, 1));
}
return (f[i][j] = ans);
};
return dfs(0, 0);
}
```
```ts
function maxProfit(prices: number[]): number {
const n = prices.length;
const f: number[][] = Array.from({ length: n }, () => Array.from({ length: 2 }, () => 0));
f[0][1] = -prices[0];
for (let i = 1; i < n; ++i) {
f[i][0] = Math.max(f[i - 1][0], f[i - 1][1] + prices[i]);
f[i][1] = Math.max(f[i - 1][1], (i > 1 ? f[i - 2][0] : 0) - prices[i]);
}
return f[n - 1][0];
}
```
```ts
function maxProfit(prices: number[]): number {
let [f, f0, f1] = [0, 0, -prices[0]];
for (const x of prices.slice(1)) {
[f, f0, f1] = [f0, Math.max(f0, f1 + x), Math.max(f1, f - x)];
}
return f0;
}
```
### **...**
```
Expand Down