From d178871e8329d89fc98e7661a92bf928d6ee10af Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Fri, 23 Dec 2022 01:16:10 +0800 Subject: [PATCH 1/7] =?UTF-8?q?update=200139.=E5=8D=95=E8=AF=8D=E6=8B=86?= =?UTF-8?q?=E5=88=86=EF=BC=9A=E4=BC=98=E5=8C=96=E6=96=87=E6=9C=AC=20?= =?UTF-8?q?=E5=92=8C=20go=20=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0139.单词拆分.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/problems/0139.单词拆分.md b/problems/0139.单词拆分.md index f06bd40c..f76d8075 100644 --- a/problems/0139.单词拆分.md +++ b/problems/0139.单词拆分.md @@ -138,7 +138,7 @@ public: 3. dp数组如何初始化 -从递归公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递归的根基,dp[0]一定要为true,否则递归下去后面都都是false了。 +从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。 那么dp[0]有没有意义呢? @@ -152,13 +152,13 @@ dp[0]表示如果字符串为空的话,说明出现在字典里。 题目中说是拆分为一个或多个在字典中出现的单词,所以这是完全背包。 -还要讨论两层for循环的前后循序。 +还要讨论两层for循环的前后顺序。 **如果求组合数就是外层for循环遍历物品,内层for遍历背包**。 **如果求排列数就是外层for遍历背包,内层for循环遍历物品**。 -我在这里做一个一个总结: +我在这里做一个总结: 求组合数:[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html) 求排列数:[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和.html)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html) @@ -170,7 +170,7 @@ dp[0]表示如果字符串为空的话,说明出现在字典里。 "apple" + "apple" + "pen" 或者 "pen" + "apple" + "apple" 是不可以的,那么我们就是强调物品之间顺序。 -所以说,本题一定是 先遍历 背包,在遍历物品。 +所以说,本题一定是 先遍历 背包,再遍历物品。 5. 举例推导dp[i] @@ -209,7 +209,7 @@ public: 关于遍历顺序,再给大家讲一下为什么 先遍历物品再遍历背包不行。 -这里可以给出先遍历物品在遍历背包的代码: +这里可以给出先遍历物品再遍历背包的代码: ```CPP class Solution { @@ -241,7 +241,7 @@ public: 最后dp[s.size()] = 0 即 dp[13] = 0 ,而不是1,因为先用 "apple" 去遍历的时候,dp[8]并没有被赋值为1 (还没用"pen"),所以 dp[13]也不能变成1。 -除非是先用 "apple" 遍历一遍,在用 "pen" 遍历,此时 dp[8]已经是1,最后再用 "apple" 去遍历,dp[13]才能是1。 +除非是先用 "apple" 遍历一遍,再用 "pen" 遍历,此时 dp[8]已经是1,最后再用 "apple" 去遍历,dp[13]才能是1。 如果大家对这里不理解,建议可以把我上面给的代码,拿去力扣上跑一跑,把dp数组打印出来,对着递推公式一步一步去看,思路就清晰了。 @@ -352,16 +352,16 @@ class Solution: Go: ```Go func wordBreak(s string,wordDict []string) bool { - wordDictSet:=make(map[string]bool) - for _,w:=range wordDict{ - wordDictSet[w]=true + wordDictSet := make(map[string]bool) + for _, w := range wordDict { + wordDictSet[w] = true } - dp:=make([]bool,len(s)+1) - dp[0]=true - for i:=1;i<=len(s);i++{ - for j:=0;j Date: Sat, 24 Dec 2022 17:37:56 +0800 Subject: [PATCH 2/7] =?UTF-8?q?update=200198.=E6=89=93=E5=AE=B6=E5=8A=AB?= =?UTF-8?q?=E8=88=8D:=20=E6=9B=B4=E6=96=B0=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0198.打家劫舍.md | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/problems/0198.打家劫舍.md b/problems/0198.打家劫舍.md index 1e48f007..6002cd3a 100644 --- a/problems/0198.打家劫舍.md +++ b/problems/0198.打家劫舍.md @@ -52,7 +52,7 @@ 如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。 -如果不偷第i房间,那么dp[i] = dp[i - 1],即考虑i-1房,(**注意这里是考虑,并不是一定要偷i-1房,这是很多同学容易混淆的点**) +如果不偷第i房间,那么dp[i] = dp[i - 1],即考 虑i-1房,(**注意这里是考虑,并不是一定要偷i-1房,这是很多同学容易混淆的点**) 然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]); @@ -154,29 +154,20 @@ class Solution: Go: ```Go func rob(nums []int) int { - if len(nums)<1{ - return 0 - } - if len(nums)==1{ - return nums[0] - } - if len(nums)==2{ - return max(nums[0],nums[1]) - } - dp :=make([]int,len(nums)) - dp[0]=nums[0] - dp[1]=max(nums[0],nums[1]) - for i:=2;ib{ - return a - } - return b + if a > b { + return a + } + return b } ``` From e39209e3d7a55cd36812e8b6042f802e1e03bdde Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sat, 24 Dec 2022 17:41:56 +0800 Subject: [PATCH 3/7] =?UTF-8?q?update=200213.=E6=89=93=E5=AE=B6=E5=8A=AB?= =?UTF-8?q?=E8=88=8DII:=20=E8=B0=83=E6=8D=A2=E5=85=B6=E4=BB=96=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E4=B8=AD=20go=20=E4=BB=A3=E7=A0=81=E7=9A=84=E9=A1=BA?= =?UTF-8?q?=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0213.打家劫舍II.md | 76 ++++++++++++++++----------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/problems/0213.打家劫舍II.md b/problems/0213.打家劫舍II.md index 8e1ca126..dd109f83 100644 --- a/problems/0213.打家劫舍II.md +++ b/problems/0213.打家劫舍II.md @@ -143,6 +143,44 @@ class Solution: return dp[-1] ``` +Go: + +```go +// 打家劫舍Ⅱ 动态规划 +// 时间复杂度O(n) 空间复杂度O(n) +func rob(nums []int) int { + if len(nums) == 1 { + return nums[0] + } + if len(nums) == 2 { + return max(nums[0], nums[1]) + } + + result1 := robRange(nums, 0) + result2 := robRange(nums, 1) + return max(result1, result2) +} + +// 偷盗指定的范围 +func robRange(nums []int, start int) int { + dp := make([]int, len(nums)) + dp[1] = nums[start] + + for i := 2; i < len(nums); i++ { + dp[i] = max(dp[i - 2] + nums[i - 1 + start], dp[i - 1]) + } + + return dp[len(nums) - 1] +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + javascipt: ```javascript var rob = function(nums) { @@ -187,44 +225,6 @@ function robRange(nums: number[], start: number, end: number): number { } ``` -Go: - -```go -// 打家劫舍Ⅱ 动态规划 -// 时间复杂度O(n) 空间复杂度O(n) -func rob(nums []int) int { - if len(nums) == 1 { - return nums[0] - } - if len(nums) == 2 { - return max(nums[0], nums[1]) - } - - result1 := robRange(nums, 0) - result2 := robRange(nums, 1) - return max(result1, result2) -} - -// 偷盗指定的范围 -func robRange(nums []int, start int) int { - dp := make([]int, len(nums)) - dp[1] = nums[start] - - for i := 2; i < len(nums); i++ { - dp[i] = max(dp[i - 2] + nums[i - 1 + start], dp[i - 1]) - } - - return dp[len(nums) - 1] -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} -``` -

From a9034c491081324e49edd160184e3c99ef91dd54 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sat, 24 Dec 2022 17:54:59 +0800 Subject: [PATCH 4/7] =?UTF-8?q?update=200337.=E6=89=93=E5=AE=B6=E5=8A=AB?= =?UTF-8?q?=E8=88=8DIII=EF=BC=9A=E5=88=A0=E9=99=A4=E5=86=97=E4=BD=99?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0337.打家劫舍III.md | 35 ++------------------------------ 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/problems/0337.打家劫舍III.md b/problems/0337.打家劫舍III.md index c69279fd..ba9a2e59 100644 --- a/problems/0337.打家劫舍III.md +++ b/problems/0337.打家劫舍III.md @@ -129,7 +129,7 @@ if (cur == NULL) return vector{0, 0}; 3. 确定遍历顺序 -首先明确的是使用后序遍历。 因为通过递归函数的返回值来做下一步计算。 +首先明确的是使用后序遍历。 因为要通过递归函数的返回值来做下一步计算。 通过递归左节点,得到左节点偷与不偷的金钱。 @@ -147,7 +147,7 @@ vector right = robTree(cur->right); // 右 4. 确定单层递归的逻辑 -如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; (**如果对下标含义不理解就在回顾一下dp数组的含义**) +如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; (**如果对下标含义不理解就再回顾一下dp数组的含义**) 如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]); @@ -483,37 +483,6 @@ function robNode(node: TreeNode | null): MaxValueArr { } ``` -### Go - -```go -// 打家劫舍Ⅲ 动态规划 -// 时间复杂度O(n) 空间复杂度O(logn) -func rob(root *TreeNode) int { - dp := traversal(root) - return max(dp[0], dp[1]) -} - -func traversal(cur *TreeNode) []int { - if cur == nil { - return []int{0, 0} - } - - dpL := traversal(cur.Left) - dpR := traversal(cur.Right) - - val1 := cur.Val + dpL[0] + dpR[0] // 偷盗当前节点 - val2 := max(dpL[0], dpL[1]) + max(dpR[0], dpR[1]) // 不偷盗当前节点 - return []int{val2, val1} -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} -``` -

From c94a8a951a5dbddce848b8517d362c2eb041bd19 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sat, 24 Dec 2022 20:04:07 +0800 Subject: [PATCH 5/7] =?UTF-8?q?update=200121.=E4=B9=B0=E5=8D=96=E8=82=A1?= =?UTF-8?q?=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BA=EF=BC=9A?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0121.买卖股票的最佳时机.md | 67 ++++++++------------ 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/problems/0121.买卖股票的最佳时机.md b/problems/0121.买卖股票的最佳时机.md index 915b178a..8736c9f3 100644 --- a/problems/0121.买卖股票的最佳时机.md +++ b/problems/0121.买卖股票的最佳时机.md @@ -89,7 +89,7 @@ dp[i][1] 表示第i天不持有股票所得最多现金 **注意这里说的是“持有”,“持有”不代表就是当天“买入”!也有可能是昨天就买入了,今天保持持有的状态** -很多同学把“持有”和“买入”没分区分清楚。 +很多同学把“持有”和“买入”没区分清楚。 在下面递推公式分析中,我会进一步讲解。 @@ -103,11 +103,11 @@ dp[i][1] 表示第i天不持有股票所得最多现金 如果第i天不持有股票即dp[i][1], 也可以由两个状态推出来 * 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1] -* 第i天卖出股票,所得现金就是按照今天股票佳价格卖出后所得现金即:prices[i] + dp[i - 1][0] +* 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金即:prices[i] + dp[i - 1][0] 同样dp[i][1]取最大的,dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]); -这样递归公式我们就分析完了 +这样递推公式我们就分析完了 3. dp数组如何初始化 @@ -121,7 +121,7 @@ dp[0][1]表示第0天不持有股票,不持有股票那么现金就是0,所 4. 确定遍历顺序 -从递推公式可以看出dp[i]都是有dp[i - 1]推导出来的,那么一定是从前向后遍历。 +从递推公式可以看出dp[i]都是由dp[i - 1]推导出来的,那么一定是从前向后遍历。 5. 举例推导dp数组 @@ -326,53 +326,40 @@ Go: > 贪心法: ```Go func maxProfit(prices []int) int { - low := math.MaxInt32 - rlt := 0 - for i := range prices{ - low = min(low, prices[i]) - rlt = max(rlt, prices[i]-low) + min := prices[0] + res := 0 + for i := 1; i < len(prices); i++ { + if prices[i] - min > res { + res = prices[i]-min + } + if min > prices[i] { + min = prices[i] + } } - - return rlt -} -func min(a, b int) int { - if a < b{ - return a - } - - return b -} - -func max(a, b int) int { - if a > b{ - return a - } - - return b + return res } ``` > 动态规划:版本一 ```Go func maxProfit(prices []int) int { - length:=len(prices) - if length==0{return 0} - dp:=make([][]int,length) - for i:=0;ib{ +func max(a, b int) int { + if a > b { return a } return b @@ -385,7 +372,7 @@ func maxProfit(prices []int) int { dp := [2][2]int{} dp[0][0] = -prices[0] dp[0][1] = 0 - for i := 1; i < len(prices); i++{ + for i := 1; i < len(prices); i++ { dp[i%2][0] = max(dp[(i-1)%2][0], -prices[i]) dp[i%2][1] = max(dp[(i-1)%2][1], dp[(i-1)%2][0]+prices[i]) } From 18e062c3e6b8cc8b1f068ca74b61a9ba42432392 Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sat, 24 Dec 2022 20:19:05 +0800 Subject: [PATCH 6/7] =?UTF-8?q?update=200122.=E4=B9=B0=E5=8D=96=E8=82=A1?= =?UTF-8?q?=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BAII?= =?UTF-8?q?=EF=BC=88=E5=8A=A8=E6=80=81=E8=A7=84=E5=88=92=EF=BC=89=EF=BC=9A?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E5=AD=97=E5=92=8C=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E5=86=97=E4=BD=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...票的最佳时机II(动态规划).md | 31 +++---------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/problems/0122.买卖股票的最佳时机II(动态规划).md b/problems/0122.买卖股票的最佳时机II(动态规划).md index f2aec68b..2779083d 100644 --- a/problems/0122.买卖股票的最佳时机II(动态规划).md +++ b/problems/0122.买卖股票的最佳时机II(动态规划).md @@ -39,7 +39,7 @@ 本题我们在讲解贪心专题的时候就已经讲解过了[贪心算法:买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html),只不过没有深入讲解动态规划的解法,那么这次我们再好好分析一下动规的解法。 -本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的唯一区别本题股票可以买卖多次了(注意只有一只股票,所以再次购买前要出售掉之前的股票) +本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的唯一区别是本题股票可以买卖多次了(注意只有一只股票,所以再次购买前要出售掉之前的股票) **在动规五部曲中,这个区别主要是体现在递推公式上,其他都和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)一样一样的**。 @@ -63,9 +63,9 @@ 那么第i天持有股票即dp[i][0],如果是第i天买入股票,所得现金就是昨天不持有股票的所得现金 减去 今天的股票价格 即:dp[i - 1][1] - prices[i]。 -在来看看如果第i天不持有股票即dp[i][1]的情况, 依然可以由两个状态推出来 +再来看看如果第i天不持有股票即dp[i][1]的情况, 依然可以由两个状态推出来 * 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1] -* 第i天卖出股票,所得现金就是按照今天股票佳价格卖出后所得现金即:prices[i] + dp[i - 1][0] +* 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金即:prices[i] + dp[i - 1][0] **注意这里和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)就是一样的逻辑,卖出股票收获利润(可能是负值)天经地义!** @@ -99,7 +99,7 @@ dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); **这正是因为本题的股票可以买卖多次!** 所以买入股票的时候,可能会有之前买卖的利润即:dp[i - 1][1],所以dp[i - 1][1] - prices[i]。 -想到到这一点,对这两道题理解的比较深刻了。 +想到到这一点,对这两道题理解的就比较深刻了。 这里我依然给出滚动数组的版本,C++代码如下: @@ -228,29 +228,6 @@ func max(a, b int) int { } ``` -```go -func maxProfit(prices []int) int { - //创建数组 - dp:=make([][]int,len(prices)) - for i:=0;i Date: Sat, 24 Dec 2022 21:15:31 +0800 Subject: [PATCH 7/7] =?UTF-8?q?update=200123.=E4=B9=B0=E5=8D=96=E8=82=A1?= =?UTF-8?q?=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6=E6=9C=BAIII?= =?UTF-8?q?=EF=BC=9A=E5=88=A0=E9=99=A4=E5=86=97=E4=BD=99=20go=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0123.买卖股票的最佳时机III.md | 71 +++++-------------- 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md index 611bd2ce..d480da83 100644 --- a/problems/0123.买卖股票的最佳时机III.md +++ b/problems/0123.买卖股票的最佳时机III.md @@ -62,7 +62,7 @@ dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天 需要注意:dp[i][1],**表示的是第i天,买入股票的状态,并不是说一定要第i天买入股票,这是很多同学容易陷入的误区**。 -例如 dp[i][1] ,并不是说 第i点一定买入股票,有可能 第 i-1天 就买入了,那么 dp[i][1] 延续买入股票的这个状态。 +例如 dp[i][1] ,并不是说 第i天一定买入股票,有可能 第 i-1天 就买入了,那么 dp[i][1] 延续买入股票的这个状态。 2. 确定递推公式 @@ -102,7 +102,7 @@ dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]); 第0天第二次买入操作,初始值应该是多少呢?应该不少同学疑惑,第一次还没买入呢,怎么初始化第二次买入呢? -第二次买入依赖于第一次卖出的状态,其实相当于第0天第一次买入了,第一次卖出了,然后在买入一次(第二次买入),那么现在手头上没有现金,只要买入,现金就做相应的减少。 +第二次买入依赖于第一次卖出的状态,其实相当于第0天第一次买入了,第一次卖出了,然后再买入一次(第二次买入),那么现在手头上没有现金,只要买入,现金就做相应的减少。 所以第二次买入操作,初始化为:dp[0][3] = -prices[0]; @@ -181,7 +181,7 @@ public: dp[1] = max(dp[1], dp[0] - prices[i]); 如果dp[1]取dp[1],即保持买入股票的状态,那么 dp[2] = max(dp[2], dp[1] + prices[i]);中dp[1] + prices[i] 就是今天卖出。 -如果dp[1]取dp[0] - prices[i],今天买入股票,那么dp[2] = max(dp[2], dp[1] + prices[i]);中的dp[1] + prices[i]相当于是尽在再卖出股票,一买一卖收益为0,对所得现金没有影响。相当于今天买入股票又卖出股票,等于没有操作,保持昨天卖出股票的状态了。 +如果dp[1]取dp[0] - prices[i],今天买入股票,那么dp[2] = max(dp[2], dp[1] + prices[i]);中的dp[1] + prices[i]相当于是今天再卖出股票,一买一卖收益为0,对所得现金没有影响。相当于今天买入股票又卖出股票,等于没有操作,保持昨天卖出股票的状态了。 **这种写法看上去简单,其实思路很绕,不建议大家这么写,这么思考,很容易把自己绕进去!** @@ -312,26 +312,26 @@ Go: ```go func maxProfit(prices []int) int { - dp:=make([][]int,len(prices)) - for i:=0;ib{ +func max(a, b int) int { + if a > b { return a } return b @@ -407,39 +407,6 @@ function maxProfit(prices: number[]): number { }; ``` -Go: - -> 版本一: -```go -// 买卖股票的最佳时机III 动态规划 -// 时间复杂度O(n) 空间复杂度O(n) -func maxProfit(prices []int) int { - dp := make([][]int, len(prices)) - status := make([]int, len(prices) * 4) - for i := range dp { - dp[i] = status[:4] - status = status[4:] - } - dp[0][0], dp[0][2] = -prices[0], -prices[0] - - for i := 1; i < len(prices); i++ { - dp[i][0] = max(dp[i - 1][0], -prices[i]) - dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]) - dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] - prices[i]) - dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] + prices[i]) - } - - return dp[len(prices) - 1][3] -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} -``` -