From 5e0ab494756cb48b11450f997f56c2677f51dcc4 Mon Sep 17 00:00:00 2001 From: Lane Zhang Date: Fri, 22 Nov 2024 10:57:51 +0800 Subject: [PATCH 1/3] =?UTF-8?q?0123,=200188,=200309=20=E8=82=A1=E7=A5=A8?= =?UTF-8?q?=E7=B1=BB=E9=97=AE=E9=A2=98=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=98=93?= =?UTF-8?q?=E7=90=86=E8=A7=A3=E7=9A=84=E4=B8=80=E7=BB=B4=20dp=20Python=20?= =?UTF-8?q?=E5=92=8C=20Go=20=E7=89=88=E6=9C=AC=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0123.买卖股票的最佳时机III.md | 29 +++++++++- .../0188.买卖股票的最佳时机IV.md | 56 +++++++++++++++++-- ...09.最佳买卖股票时机含冷冻期.md | 35 +++++++++++- 3 files changed, 110 insertions(+), 10 deletions(-) diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md index 8e224a89..1b7c09d2 100644 --- a/problems/0123.买卖股票的最佳时机III.md +++ b/problems/0123.买卖股票的最佳时机III.md @@ -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: > 版本一: diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md index 0b1622ac..cbba12c9 100644 --- a/problems/0188.买卖股票的最佳时机IV.md +++ b/problems/0188.买卖股票的最佳时机IV.md @@ -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: diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md index 4913b8bd..707b1532 100644 --- a/problems/0309.最佳买卖股票时机含冷冻期.md +++ b/problems/0309.最佳买卖股票时机含冷冻期.md @@ -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 From e40ddd5cbf46ae62a0b1aee4b683fb899b6fd6c8 Mon Sep 17 00:00:00 2001 From: Lane Zhang Date: Fri, 22 Nov 2024 10:59:16 +0800 Subject: [PATCH 2/3] =?UTF-8?q?0337.=E6=89=93=E5=AE=B6=E5=8A=AB=E8=88=8DII?= =?UTF-8?q?I.md=20=E4=BD=BF=E7=94=A8=20`slices.Max`=20=E6=9B=BF=E4=BB=A3?= =?UTF-8?q?=E6=89=8B=E5=B7=A5max=20func=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0337.打家劫舍III.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/problems/0337.打家劫舍III.md b/problems/0337.打家劫舍III.md index 12e31aba..a3130df7 100644 --- a/problems/0337.打家劫舍III.md +++ b/problems/0337.打家劫舍III.md @@ -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} From 332302b998306ca16e253deeff637075ee49e555 Mon Sep 17 00:00:00 2001 From: Lane Zhang Date: Fri, 22 Nov 2024 10:59:39 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=8A=A8=E6=80=81=E8=A7=84=E5=88=92?= =?UTF-8?q?=E7=90=86=E8=AE=BA=E5=9F=BA=E7=A1=80.md=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E9=94=99=E5=AD=97=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/动态规划理论基础.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/动态规划理论基础.md b/problems/动态规划理论基础.md index c9420d24..9ffb4533 100644 --- a/problems/动态规划理论基础.md +++ b/problems/动态规划理论基础.md @@ -106,7 +106,7 @@ **如果这灵魂三问自己都做到了,基本上这道题目也就解决了**,或者更清晰的知道自己究竟是哪一点不明白,是状态转移不明白,还是实现代码不知道该怎么写,还是不理解遍历dp数组的顺序。 -然后在问问题,目的性就很强了,群里的小伙伴也可以快速知道提问者的疑惑了。 +然后再问问题,目的性就很强了,群里的小伙伴也可以快速知道提问者的疑惑了。 **注意这里不是说不让大家问问题哈, 而是说问问题之前要有自己的思考,问题要问到点子上!**