From 22615387a5966b8930076b08abe29ae22ce8ce8a Mon Sep 17 00:00:00 2001 From: jianghongcheng <35664721+jianghongcheng@users.noreply.github.com> Date: Tue, 6 Jun 2023 10:25:25 -0500 Subject: [PATCH 1/6] =?UTF-8?q?Update=200309.=E6=9C=80=E4=BD=B3=E4=B9=B0?= =?UTF-8?q?=E5=8D=96=E8=82=A1=E7=A5=A8=E6=97=B6=E6=9C=BA=E5=90=AB=E5=86=B7?= =?UTF-8?q?=E5=86=BB=E6=9C=9F.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...09.最佳买卖股票时机含冷冻期.md | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md index a56d9b84..67f6d564 100644 --- a/problems/0309.最佳买卖股票时机含冷冻期.md +++ b/problems/0309.最佳买卖股票时机含冷冻期.md @@ -248,23 +248,51 @@ class Solution { ``` Python: - +版本一 ```python +from typing import List + class Solution: def maxProfit(self, prices: List[int]) -> int: n = len(prices) if n == 0: return 0 - dp = [[0] * 4 for _ in range(n)] - dp[0][0] = -prices[0] #持股票 + dp = [[0] * 4 for _ in range(n)] # 创建动态规划数组,4个状态分别表示持有股票、不持有股票且处于冷冻期、不持有股票且不处于冷冻期、不持有股票且当天卖出后处于冷冻期 + dp[0][0] = -prices[0] # 初始状态:第一天持有股票的最大利润为买入股票的价格 for i in range(1, n): - dp[i][0] = max(dp[i-1][0], max(dp[i-1][3], dp[i-1][1]) - prices[i]) - dp[i][1] = max(dp[i-1][1], dp[i-1][3]) - dp[i][2] = dp[i-1][0] + prices[i] - dp[i][3] = dp[i-1][2] - return max(dp[n-1][3], dp[n-1][1], dp[n-1][2]) -``` + dp[i][0] = max(dp[i-1][0], max(dp[i-1][3], dp[i-1][1]) - prices[i]) # 当前持有股票的最大利润等于前一天持有股票的最大利润或者前一天不持有股票且不处于冷冻期的最大利润减去当前股票的价格 + dp[i][1] = max(dp[i-1][1], dp[i-1][3]) # 当前不持有股票且处于冷冻期的最大利润等于前一天持有股票的最大利润加上当前股票的价格 + dp[i][2] = dp[i-1][0] + prices[i] # 当前不持有股票且不处于冷冻期的最大利润等于前一天不持有股票的最大利润或者前一天处于冷冻期的最大利润 + dp[i][3] = dp[i-1][2] # 当前不持有股票且当天卖出后处于冷冻期的最大利润等于前一天不持有股票且不处于冷冻期的最大利润 + return max(dp[n-1][3], dp[n-1][1], dp[n-1][2]) # 返回最后一天不持有股票的最大利润 +``` +版本二 +```python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + n = len(prices) + if n < 2: + return 0 + + # 定义三种状态的动态规划数组 + dp = [[0] * 3 for _ in range(n)] + dp[0][0] = -prices[0] # 持有股票的最大利润 + dp[0][1] = 0 # 不持有股票,且处于冷冻期的最大利润 + dp[0][2] = 0 # 不持有股票,不处于冷冻期的最大利润 + + for i in range(1, n): + # 当前持有股票的最大利润等于前一天持有股票的最大利润或者前一天不持有股票且不处于冷冻期的最大利润减去当前股票的价格 + dp[i][0] = max(dp[i-1][0], dp[i-1][2] - prices[i]) + # 当前不持有股票且处于冷冻期的最大利润等于前一天持有股票的最大利润加上当前股票的价格 + dp[i][1] = dp[i-1][0] + prices[i] + # 当前不持有股票且不处于冷冻期的最大利润等于前一天不持有股票的最大利润或者前一天处于冷冻期的最大利润 + dp[i][2] = max(dp[i-1][2], dp[i-1][1]) + + # 返回最后一天不持有股票的最大利润 + return max(dp[-1][1], dp[-1][2]) + +``` Go: ```go // 最佳买卖股票时机含冷冻期 动态规划 From d3a07fa1bd7c325188a416486daa7a85e6816680 Mon Sep 17 00:00:00 2001 From: jianghongcheng <35664721+jianghongcheng@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:29:07 -0500 Subject: [PATCH 2/6] =?UTF-8?q?Update=200300.=E6=9C=80=E9=95=BF=E4=B8=8A?= =?UTF-8?q?=E5=8D=87=E5=AD=90=E5=BA=8F=E5=88=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0300.最长上升子序列.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md index 01d34949..98d7b14f 100644 --- a/problems/0300.最长上升子序列.md +++ b/problems/0300.最长上升子序列.md @@ -141,7 +141,7 @@ class Solution { } } ``` - +DP Python: ```python class Solution: @@ -157,7 +157,31 @@ class Solution: result = max(result, dp[i]) #取长的子序列 return result ``` +贪心 +```python +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + if len(nums) <= 1: + return len(nums) + + tails = [nums[0]] # 存储递增子序列的尾部元素 + for num in nums[1:]: + if num > tails[-1]: + tails.append(num) # 如果当前元素大于递增子序列的最后一个元素,直接加入到子序列末尾 + else: + # 使用二分查找找到当前元素在递增子序列中的位置,并替换对应位置的元素 + left, right = 0, len(tails) - 1 + while left < right: + mid = (left + right) // 2 + if tails[mid] < num: + left = mid + 1 + else: + right = mid + tails[left] = num + + return len(tails) # 返回递增子序列的长度 +``` Go: ```go // 动态规划求解 From a7d546ca2a6c7af9df378b3928c58f373177ed54 Mon Sep 17 00:00:00 2001 From: jianghongcheng <35664721+jianghongcheng@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:29:32 -0500 Subject: [PATCH 3/6] =?UTF-8?q?Update=200300.=E6=9C=80=E9=95=BF=E4=B8=8A?= =?UTF-8?q?=E5=8D=87=E5=AD=90=E5=BA=8F=E5=88=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0300.最长上升子序列.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md index 98d7b14f..54249331 100644 --- a/problems/0300.最长上升子序列.md +++ b/problems/0300.最长上升子序列.md @@ -141,8 +141,10 @@ class Solution { } } ``` -DP + Python: + +DP ```python class Solution: def lengthOfLIS(self, nums: List[int]) -> int: From c652187f747a2b7546f45e0f29cc985b929a8454 Mon Sep 17 00:00:00 2001 From: jianghongcheng <35664721+jianghongcheng@users.noreply.github.com> Date: Wed, 7 Jun 2023 03:59:52 -0500 Subject: [PATCH 4/6] =?UTF-8?q?Update=200674.=E6=9C=80=E9=95=BF=E8=BF=9E?= =?UTF-8?q?=E7=BB=AD=E9=80=92=E5=A2=9E=E5=BA=8F=E5=88=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0674.最长连续递增序列.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/problems/0674.最长连续递增序列.md b/problems/0674.最长连续递增序列.md index 79a8311d..0d9866a0 100644 --- a/problems/0674.最长连续递增序列.md +++ b/problems/0674.最长连续递增序列.md @@ -204,7 +204,7 @@ public static int findLengthOfLCIS(int[] nums) { Python: -> 动态规划: +DP ```python class Solution: def findLengthOfLCIS(self, nums: List[int]) -> int: @@ -219,8 +219,27 @@ class Solution: return result ``` +DP(优化版) +```python +class Solution: + def findLengthOfLCIS(self, nums: List[int]) -> int: + if not nums: + return 0 -> 贪心法: + max_length = 1 + current_length = 1 + + for i in range(1, len(nums)): + if nums[i] > nums[i - 1]: + current_length += 1 + max_length = max(max_length, current_length) + else: + current_length = 1 + + return max_length + +``` +贪心 ```python class Solution: def findLengthOfLCIS(self, nums: List[int]) -> int: From 8fb169701478cce21d5bfba761289479a0e27fbd Mon Sep 17 00:00:00 2001 From: jianghongcheng <35664721+jianghongcheng@users.noreply.github.com> Date: Wed, 7 Jun 2023 05:26:40 -0500 Subject: [PATCH 5/6] =?UTF-8?q?Update=200718.=E6=9C=80=E9=95=BF=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=AD=90=E6=95=B0=E7=BB=84.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0718.最长重复子数组.md | 96 +++++++++++++++++++++----- 1 file changed, 79 insertions(+), 17 deletions(-) diff --git a/problems/0718.最长重复子数组.md b/problems/0718.最长重复子数组.md index 08be6732..78ef7ddd 100644 --- a/problems/0718.最长重复子数组.md +++ b/problems/0718.最长重复子数组.md @@ -247,37 +247,99 @@ class Solution { Python: -> 动态规划: +2维DP ```python class Solution: - def findLength(self, A: List[int], B: List[int]) -> int: - dp = [[0] * (len(B)+1) for _ in range(len(A)+1)] + def findLength(self, nums1: List[int], nums2: List[int]) -> int: + # 创建一个二维数组 dp,用于存储最长公共子数组的长度 + dp = [[0] * (len(nums2) + 1) for _ in range(len(nums1) + 1)] + # 记录最长公共子数组的长度 result = 0 - for i in range(1, len(A)+1): - for j in range(1, len(B)+1): - if A[i-1] == B[j-1]: - dp[i][j] = dp[i-1][j-1] + 1 - result = max(result, dp[i][j]) + + # 遍历数组 nums1 + for i in range(1, len(nums1) + 1): + # 遍历数组 nums2 + for j in range(1, len(nums2) + 1): + # 如果 nums1[i-1] 和 nums2[j-1] 相等 + if nums1[i - 1] == nums2[j - 1]: + # 在当前位置上的最长公共子数组长度为前一个位置上的长度加一 + dp[i][j] = dp[i - 1][j - 1] + 1 + # 更新最长公共子数组的长度 + if dp[i][j] > result: + result = dp[i][j] + + # 返回最长公共子数组的长度 return result + ``` -> 动态规划:滚动数组 +1维DP ```python class Solution: - def findLength(self, A: List[int], B: List[int]) -> int: - dp = [0] * (len(B) + 1) + def findLength(self, nums1: List[int], nums2: List[int]) -> int: + # 创建一个一维数组 dp,用于存储最长公共子数组的长度 + dp = [0] * (len(nums2) + 1) + # 记录最长公共子数组的长度 result = 0 - for i in range(1, len(A)+1): - for j in range(len(B), 0, -1): - if A[i-1] == B[j-1]: - dp[j] = dp[j-1] + 1 + + # 遍历数组 nums1 + for i in range(1, len(nums1) + 1): + # 用于保存上一个位置的值 + prev = 0 + # 遍历数组 nums2 + for j in range(1, len(nums2) + 1): + # 保存当前位置的值,因为会在后面被更新 + current = dp[j] + # 如果 nums1[i-1] 和 nums2[j-1] 相等 + if nums1[i - 1] == nums2[j - 1]: + # 在当前位置上的最长公共子数组长度为上一个位置的长度加一 + dp[j] = prev + 1 + # 更新最长公共子数组的长度 + if dp[j] > result: + result = dp[j] else: - dp[j] = 0 #注意这里不相等的时候要有赋0的操作 - result = max(result, dp[j]) + # 如果不相等,将当前位置的值置为零 + dp[j] = 0 + # 更新 prev 变量为当前位置的值,供下一次迭代使用 + prev = current + + # 返回最长公共子数组的长度 return result + ``` +2维DP 扩展 +```python +class Solution: + def findLength(self, nums1: List[int], nums2: List[int]) -> int: + # 创建一个二维数组 dp,用于存储最长公共子数组的长度 + dp = [[0] * (len(nums2) + 1) for _ in range(len(nums1) + 1)] + # 记录最长公共子数组的长度 + result = 0 + # 对第一行和第一列进行初始化 + for i in range(len(nums1)): + if nums1[i] == nums2[0]: + dp[i + 1][1] = 1 + for j in range(len(nums2)): + if nums1[0] == nums2[j]: + dp[1][j + 1] = 1 + + # 填充dp数组 + for i in range(1, len(nums1) + 1): + for j in range(1, len(nums2) + 1): + if nums1[i - 1] == nums2[j - 1]: + # 如果 nums1[i-1] 和 nums2[j-1] 相等,则当前位置的最长公共子数组长度为左上角位置的值加一 + dp[i][j] = dp[i - 1][j - 1] + 1 + if dp[i][j] > result: + # 更新最长公共子数组的长度 + result = dp[i][j] + + # 返回最长公共子数组的长度 + return result + + +``` Go: ```Go func findLength(A []int, B []int) int { From 0a742d83a49e942324163fc0e7642cd1dfd7010f Mon Sep 17 00:00:00 2001 From: jianghongcheng <35664721+jianghongcheng@users.noreply.github.com> Date: Wed, 7 Jun 2023 05:32:55 -0500 Subject: [PATCH 6/6] =?UTF-8?q?Update=201143.=E6=9C=80=E9=95=BF=E5=85=AC?= =?UTF-8?q?=E5=85=B1=E5=AD=90=E5=BA=8F=E5=88=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/1143.最长公共子序列.md | 48 ++++++++++++++++++++------ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/problems/1143.最长公共子序列.md b/problems/1143.最长公共子序列.md index 730e9ad1..4b712569 100644 --- a/problems/1143.最长公共子序列.md +++ b/problems/1143.最长公共子序列.md @@ -198,21 +198,49 @@ class Solution { ``` Python: - +2维DP ```python class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: - len1, len2 = len(text1)+1, len(text2)+1 - dp = [[0 for _ in range(len1)] for _ in range(len2)] # 先对dp数组做初始化操作 - for i in range(1, len2): - for j in range(1, len1): # 开始列出状态转移方程 - if text1[j-1] == text2[i-1]: - dp[i][j] = dp[i-1][j-1]+1 + # 创建一个二维数组 dp,用于存储最长公共子序列的长度 + dp = [[0] * (len(text2) + 1) for _ in range(len(text1) + 1)] + + # 遍历 text1 和 text2,填充 dp 数组 + for i in range(1, len(text1) + 1): + for j in range(1, len(text2) + 1): + if text1[i - 1] == text2[j - 1]: + # 如果 text1[i-1] 和 text2[j-1] 相等,则当前位置的最长公共子序列长度为左上角位置的值加一 + dp[i][j] = dp[i - 1][j - 1] + 1 else: - dp[i][j] = max(dp[i-1][j], dp[i][j-1]) - return dp[-1][-1] -``` + # 如果 text1[i-1] 和 text2[j-1] 不相等,则当前位置的最长公共子序列长度为上方或左方的较大值 + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + + # 返回最长公共子序列的长度 + return dp[len(text1)][len(text2)] +``` +1维DP +```python +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + m, n = len(text1), len(text2) + dp = [0] * (n + 1) # 初始化一维DP数组 + + for i in range(1, m + 1): + prev = 0 # 保存上一个位置的最长公共子序列长度 + for j in range(1, n + 1): + curr = dp[j] # 保存当前位置的最长公共子序列长度 + if text1[i - 1] == text2[j - 1]: + # 如果当前字符相等,则最长公共子序列长度加一 + dp[j] = prev + 1 + else: + # 如果当前字符不相等,则选择保留前一个位置的最长公共子序列长度中的较大值 + dp[j] = max(dp[j], dp[j - 1]) + prev = curr # 更新上一个位置的最长公共子序列长度 + + return dp[n] # 返回最后一个位置的最长公共子序列长度作为结果 + +``` Go: ```Go