diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md index def69277..0b1622ac 100644 --- a/problems/0188.买卖股票的最佳时机IV.md +++ b/problems/0188.买卖股票的最佳时机IV.md @@ -404,6 +404,47 @@ func max188(a, b int) int { } ``` +版本三:空间优化版本 + +```go +func maxProfit(k int, prices []int) int { + n := len(prices) + // k次交易,2 * k种状态 + // 状态从1开始计算,避免判断 + // 奇数时持有(保持或买入) + // 偶数时不持有(保持或卖出) + dp := make([][]int, 2) + dp[0] = make([]int, k * 2 + 1) + dp[1] = make([]int, k * 2 + 1) + + // 奇数状态时持有,i += 2 + for i := 1; i <= k * 2; i += 2 { + dp[0][i] = -prices[0] + } + + for i := 1; i < len(prices); i++ { + for j := 1; j <= k * 2; j++ { + if j % 2 == 1 { + dp[i % 2][j] = max(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - 1] - prices[i]) + } else { + dp[i % 2][j] = max(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - 1] + prices[i]) + } + } + } + + return dp[(n - 1) % 2][k * 2] +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + + + ### JavaScript: ```javascript @@ -558,3 +599,4 @@ impl Solution { + diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md index 95689a48..4913b8bd 100644 --- a/problems/0309.最佳买卖股票时机含冷冻期.md +++ b/problems/0309.最佳买卖股票时机含冷冻期.md @@ -357,6 +357,42 @@ func max(a, b int) int { } ``` +```go +// 一维优化版本 +// 时间复杂度O(n), 空间复杂度O(1) +func maxProfit(prices []int) int { + + // 0: 持有,一直持有和买入 + // 1: 不持有,一直不持有(不包含前一天卖出,因为这样的一天是冷静期,状态有区别) + // 2:不持有,今天卖出 + // 3:冷静期,前一天卖出(一直不持有) + dp0, dp1, dp2, dp3 := -prices[0], 0, 0, 0 + + n := len(prices) + + for i := 1; i < n; i++ { + t0 := max(dp0, max(dp1, dp3)-prices[i]) + t1 := max(dp1, dp3) + t2 := dp0 + prices[i] + t3 := dp2 + + // 更新 + dp0, dp1, dp2, dp3 = t0, t1, t2, t3 + } + + return max(dp1, max(dp2, dp3)) +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + + + ### Javascript: > 不同的状态定义 感觉更容易理解些 @@ -540,3 +576,4 @@ impl Solution { + diff --git a/problems/0503.下一个更大元素II.md b/problems/0503.下一个更大元素II.md index 62066d85..5751bb91 100644 --- a/problems/0503.下一个更大元素II.md +++ b/problems/0503.下一个更大元素II.md @@ -168,6 +168,7 @@ class Solution { ``` ### Python: +> 版本一: ```python class Solution: @@ -181,6 +182,34 @@ class Solution: stack.append(i%len(nums)) return dp ``` + +> 版本二:针对版本一的优化 + +```python3 +class Solution: + def nextGreaterElements(self, nums: List[int]) -> List[int]: + res = [-1] * len(nums) + stack = [] + #第一次遍历nums + for i, num in enumerate(nums): + while stack and num > nums[stack[-1]]: + res[stack[-1]] = num + stack.pop() + stack.append(i) + #此时stack仍有剩余,有部分数‘无下一个更大元素’待修正 + #第二次遍历nums + for num in nums: + #一旦stack为空,就表明所有数都有下一个更大元素,可以返回结果 + if not stack: + return res + while stack and num > nums[stack[-1]]: + res[stack[-1]] = num + stack.pop() + #不要将已经有下一个更大元素的数加入栈,这样会重复赋值,只需对第一次遍历剩余的数再尝试寻找下一个更大元素即可 + #最后仍有部分最大数无法有下一个更大元素,返回结果 + return res +``` + ### Go: ```go @@ -203,7 +232,6 @@ func nextGreaterElements(nums []int) []int { return result } ``` - ### JavaScript: ```JS diff --git a/problems/0701.二叉搜索树中的插入操作.md b/problems/0701.二叉搜索树中的插入操作.md index 6b9e5834..25d39486 100644 --- a/problems/0701.二叉搜索树中的插入操作.md +++ b/problems/0701.二叉搜索树中的插入操作.md @@ -283,32 +283,10 @@ class Solution: return TreeNode(val) self.traversal(root, val) return root - ``` 递归法(版本二) ```python -class Solution: - def insertIntoBST(self, root, val): - if root is None: - return TreeNode(val) - parent = None - cur = root - while cur: - parent = cur - if val < cur.val: - cur = cur.left - else: - cur = cur.right - if val < parent.val: - parent.left = TreeNode(val) - else: - parent.right = TreeNode(val) - return root -``` - -递归法(版本三) -```python class Solution: def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]: if root is None or root.val == val: @@ -326,7 +304,7 @@ class Solution: return root ``` -递归法(版本四) +递归法(版本三) ```python class Solution: def insertIntoBST(self, root, val): @@ -340,10 +318,9 @@ class Solution: root.right = self.insertIntoBST(root.right, val) return root - ``` -迭代法 +迭代法(版本一) ```python class Solution: def insertIntoBST(self, root, val): @@ -366,10 +343,53 @@ class Solution: else: parent.right = node # 将新节点连接到父节点的右子树 - return root - - + return root ``` + +迭代法(版本二) +```python +class Solution: + def insertIntoBST(self, root, val): + if root is None: + return TreeNode(val) + parent = None + cur = root + while cur: + parent = cur + if val < cur.val: + cur = cur.left + else: + cur = cur.right + if val < parent.val: + parent.left = TreeNode(val) + else: + parent.right = TreeNode(val) + return root +``` + +迭代法(精简) +```python +class Solution: + def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]: + if not root: # 如果根节点为空,创建新节点作为根节点并返回 + return TreeNode(val) + cur = root + while cur: + if val < cur.val: + if not cur.left: # 如果此时父节点的左子树为空 + cur.left = TreeNode(val) # 将新节点连接到父节点的左子树 + return root + else: + cur = cur.left + elif val > cur.val: + if not cur.right: # 如果此时父节点的左子树为空 + cur.right = TreeNode(val) # 将新节点连接到父节点的右子树 + return root + else: + cur = cur.right + +``` + ----- ### Go diff --git a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md index 73714147..b0e8b141 100644 --- a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md +++ b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md @@ -188,6 +188,20 @@ class Solution: return max(dp[-1][0], dp[-1][1]) ``` +```python +class Solution: + def maxProfit(self, prices: List[int], fee: int) -> int: + # 持有股票手上的最大現金 + hold = -prices[0] - fee + # 不持有股票手上的最大現金 + not_hold = 0 + for price in prices[1:]: + new_hold = max(hold, not_hold - price - fee) + new_not_hold = max(not_hold, hold + price) + hold, not_hold = new_hold, new_not_hold + return not_hold +``` + ### Go: ```go diff --git a/problems/kamacoder/0044.开发商购买土地.md b/problems/kamacoder/0044.开发商购买土地.md index 37bb98ed..ea2c696e 100644 --- a/problems/kamacoder/0044.开发商购买土地.md +++ b/problems/kamacoder/0044.开发商购买土地.md @@ -388,3 +388,85 @@ if __name__ == "__main__": main() ``` +### C + +前缀和 +```c +#include +#include + +int main() +{ + int n = 0, m = 0, ret_ver = 0, ret_hor = 0; + + // 读取行和列的值 + scanf("%d%d", &n, &m); + // 动态分配数组a(横)和b(纵)的空间 + int *a = (int *)malloc(sizeof(int) * n); + int *b = (int *)malloc(sizeof(int) * m); + + // 初始化数组a和b + for (int i = 0; i < n; i++) + { + a[i] = 0; + } + for (int i = 0; i < m; i++) + { + b[i] = 0; + } + + // 读取区块权值并计算每行和每列的总权值 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < m; j++) + { + int tmp; + scanf("%d", &tmp); + a[i] += tmp; + b[j] += tmp; + } + } + + // 计算每列以及每行的前缀和 + for (int i = 1; i < n; i++) + { + a[i] += a[i - 1]; + } + for (int i = 1; i < m; i++) + { + b[i] += b[i - 1]; + } + + // 初始化ret_ver和ret_hor为最大可能值 + ret_hor = a[n - 1]; + ret_ver = b[m - 1]; + + // 计算按行划分的最小差异 + int ret2 = 0; + while (ret2 < n) + { + ret_hor = (ret_hor > abs(a[n - 1] - 2 * a[ret2])) ? abs(a[n - 1] - 2 * a[ret2]) : ret_hor; + // 原理同列,但更高级 + ret2++; + } + // 计算按列划分的最小差异 + int ret1 = 0; + while (ret1 < m) + { + if (ret_ver > abs(b[m - 1] - 2 * b[ret1])) + { + ret_ver = abs(b[m - 1] - 2 * b[ret1]); + } + ret1++; + } + + // 输出最小差异 + printf("%d\n", (ret_ver <= ret_hor) ? ret_ver : ret_hor); + + // 释放分配的内存 + free(a); + free(b); + return 0; +} + +``` diff --git a/problems/kamacoder/0058.区间和.md b/problems/kamacoder/0058.区间和.md index 5125f5f8..23e7189a 100644 --- a/problems/kamacoder/0058.区间和.md +++ b/problems/kamacoder/0058.区间和.md @@ -264,6 +264,7 @@ if __name__ == "__main__": ``` + ### JavaScript ``` JavaScript @@ -312,3 +313,47 @@ function prefixSum() { ``` + +### C + +```C +#include +#include + +int main(int argc, char *argv[]) +{ + int num; + // 读取数组长度 + scanf("%d", &num); + + // 使用动态内存分配而不是静态数组,以适应不同的输入大小 + int *a = (int *)malloc((num + 1) * sizeof(int)); + + // 初始化前缀和数组的第一个元素为0 + a[0] = 0; + + // 读取数组元素并计算前缀和 + for (int i = 1; i <= num; i++) + { + int mm; + scanf("%d", &mm); + // 累加前缀和 + a[i] = a[i - 1] + mm; + } + + int m, n; + // 循环读取区间并计算区间和,直到输入结束 + // scanf()返回成功匹配和赋值的个数,到达文件末尾则返回 EOF + while (scanf("%d%d", &m, &n) == 2) + { + // 输出区间和,注意区间是左闭右开,因此a[n+1]是包含n的元素的前缀和 + printf("%d\n", a[n+1] - a[m]); + } + + // 释放之前分配的内存 + free(a); + return 0; +} + +``` +