Merge pull request #2840 from gazeldx/stock_problems

0123, 0188, 0309 股票类问题,增加易理解的一维 dp Python 和 Go 版本。
This commit is contained in:
程序员Carl
2024-11-22 14:44:22 +08:00
committed by GitHub
5 changed files with 113 additions and 20 deletions

View File

@ -316,8 +316,9 @@ class Solution:
### Go:
> 版本一
```go
// 版本一
func maxProfit(prices []int) int {
dp := make([][]int, len(prices))
for i := 0; i < len(prices); i++ {
@ -345,8 +346,9 @@ func max(a, b int) int {
}
```
> 版本二
```go
// 版本二
func maxProfit(prices []int) int {
if len(prices) == 0 {
return 0
@ -371,8 +373,9 @@ func max(x, y int) int {
}
```
> 版本三
```go
// 版本三
func maxProfit(prices []int) int {
if len(prices) == 0 {
return 0
@ -397,6 +400,26 @@ func max(x, y int) int {
}
```
> 版本四:一维 dp 易懂版本
```go
func maxProfit(prices []int) int {
dp := make([]int, 4)
dp[0] = -prices[0]
dp[2] = -prices[0]
for _, price := range prices[1:] {
dc := slices.Clone(dp) // 这句话是关键,把前一天的 dp 状态保存下来,防止被覆盖掉,后面只用它,不用 dp逻辑简单易懂
dp[0] = max(dc[0], -price)
dp[1] = max(dc[1], dc[0] + price)
dp[2] = max(dc[2], dc[1] - price)
dp[3] = max(dc[3], dc[2] + price)
}
return dp[3]
}
```
### JavaScript:
> 版本一:

View File

@ -297,8 +297,7 @@ class Solution {
### Python:
版本一
> 版本一
```python
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
@ -313,7 +312,8 @@ class Solution:
dp[i][j+2] = max(dp[i-1][j+2], dp[i-1][j+1] + prices[i])
return dp[-1][2*k]
```
版本二
> 版本二
```python
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
@ -329,9 +329,31 @@ class Solution:
dp[j] = max(dp[j],dp[j-1]+prices[i])
return dp[2*k]
```
> 版本三: 一维 dp 数组(易理解版本)
```python
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
dp = [0] * k * 2
for i in range(k):
dp[i * 2] = -prices[0]
for price in prices[1:]:
dc = dp.copy() # 这句话是关键,把前一天的 dp 状态保存下来,防止被覆盖掉,后面只用它,不用 dp逻辑简单易懂
for i in range(2 * k):
if i % 2 == 1:
dp[i] = max(dc[i], dc[i - 1] + price)
else:
pre = 0 if i == 0 else dc[i - 1]
dp[i] = max(dc[i], pre - price)
return dp[-1]
```
### Go:
版本一:
> 版本一:
```go
// 买卖股票的最佳时机IV 动态规划
@ -368,7 +390,7 @@ func max(a, b int) int {
}
```
版本二: 三维 dp数组
> 版本二: 三维 dp数组
```go
func maxProfit(k int, prices []int) int {
length := len(prices)
@ -443,7 +465,31 @@ func max(a, b int) int {
}
```
> 版本四:一维 dp 数组(易理解版本)
```go
func maxProfit(k int, prices []int) int {
dp := make([]int, 2 * k)
for i := range k {
dp[i * 2] = -prices[0]
}
for j := 1; j < len(prices); j++ {
dc := slices.Clone(dp) // 这句话是关键,把前一天的 dp 状态保存下来,防止被覆盖掉,后面只用它,不用 dp逻辑简单易懂
for i := range k * 2 {
if i % 2 == 1 {
dp[i] = max(dc[i], dc[i - 1] + prices[j])
} else {
pre := 0; if i >= 1 { pre = dc[i - 1] }
dp[i] = max(dc[i], pre - prices[j])
}
}
}
return dp[2 * k - 1]
}
```
### JavaScript:

View File

@ -274,7 +274,7 @@ class Solution {
```
### Python
版本一
> 版本一
```python
from typing import List
@ -294,7 +294,8 @@ class Solution:
return max(dp[n-1][3], dp[n-1][1], dp[n-1][2]) # 返回最后一天不持有股票的最大利润
```
版本二
> 版本二
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
@ -320,6 +321,36 @@ class Solution:
return max(dp[-1][1], dp[-1][2])
```
> 版本三
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
# 0: holding stocks
# (1) keep holding stocks: dp[i][0] = dp[i - 1][0]
# (2) buy stocks: dp[i][0] = dp[i - 1][1] - price, or dp[i - 1][3] - price
# 1: keep no stocks: dp[i][1] = dp[i - 1][1]
# 2: sell stocks: dp[i][2] = dp[i - 1][0] + price
# 3: cooldown day: dp[i][3] = dp[i - 1][2]
dp = [-prices[0], 0, 0, 0]
for price in prices[1:]:
dc = dp.copy() # 这句话是关键,把前一天的 dp 状态保存下来,防止被覆盖掉,后面只用它,不用 dp逻辑简单易懂
dp[0] = max(
dc[0],
dc[1] - price,
dc[3] - price
)
dp[1] = max(
dc[1],
dc[3]
)
dp[2] = dc[0] + price
dp[3] = dc[2]
return max(dp)
```
### Go
```go

View File

@ -477,14 +477,7 @@ func max(x, y int) int {
```go
func rob(root *TreeNode) int {
res := robTree(root)
return max(res[0], res[1])
}
func max(a, b int) int {
if a > b {
return a
}
return b
return slices.Max(res)
}
func robTree(cur *TreeNode) []int {
@ -498,7 +491,7 @@ func robTree(cur *TreeNode) []int {
// 考虑去偷当前的屋子
robCur := cur.Val + left[0] + right[0]
// 考虑不去偷当前的屋子
notRobCur := max(left[0], left[1]) + max(right[0], right[1])
notRobCur := slices.Max(left) + slices.Max(right)
// 注意顺序0:不偷1:去偷
return []int{notRobCur, robCur}

View File

@ -106,7 +106,7 @@
**如果这灵魂三问自己都做到了,基本上这道题目也就解决了**或者更清晰的知道自己究竟是哪一点不明白是状态转移不明白还是实现代码不知道该怎么写还是不理解遍历dp数组的顺序。
然后问问题,目的性就很强了,群里的小伙伴也可以快速知道提问者的疑惑了。
然后问问题,目的性就很强了,群里的小伙伴也可以快速知道提问者的疑惑了。
**注意这里不是说不让大家问问题哈, 而是说问问题之前要有自己的思考,问题要问到点子上!**