day53 | 1143.最长公共子序列、1035.不相交的线、53. 最大子序和
发布人:shili8
发布时间:2024-12-28 02:05
阅读次数:0
**Day53**
### **1143. 最长公共子序列**
#### **问题描述**
给定两个字符串 `s1` 和 `s2`,找到它们的最长公共子序列(LCS)。如果有多个长度相同的 LCS,则返回其中一个。
#### **示例**
* 输入:`s1 = "AGGTAB"、` `s2 = "GXTXAYB"`
输出: `"GTAB"`
#### **解决方案**
我们可以使用动态规划来解决这个问题。首先,我们需要定义一个2D 数组 `dp`,其中 `dp[i][j]` 表示 `s1[0..i-1]` 和 `s2[0..j-1]` 的 LCS 的长度。
def longestCommonSubsequence(s1, s2): m, n = len(s1), len(s2) # Initialize dp array with zeros dp = [[0] * (n +1) for _ in range(m +1)] # Fill up the first row and column of dp array for i in range(1, m +1): dp[i][0] =0 for j in range(1, n +1): dp[0][j] =0 # Fill up the rest of the dp array for i in range(1, m +1): for j in range(1, n +1): if s1[i -1] == s2[j -1]: dp[i][j] = dp[i -1][j -1] +1 else: dp[i][j] = max(dp[i -1][j], dp[i][j -1]) # Reconstruct the LCS from the dp array lcs = [] i, j = m, n while i >0 and j >0: if s1[i -1] == s2[j -1]: lcs.append(s1[i -1]) i -=1 j -=1 elif dp[i -1][j] > dp[i][j -1]: i -=1 else: j -=1 return "".join(reversed(lcs))
#### **注释**
* 我们首先初始化一个 `dp` 数组,大小为 `(m +1) x (n +1)`,其中 `m` 和 `n` 是 `s1` 和 `s2` 的长度。
* 然后,我们填充了 `dp` 数组的第一行和第一列。这些值都是零,因为当一个字符串为空时,它与另一个字符串的 LCS 长度也是零。
* 接下来,我们填充了 `dp` 数组的剩余部分。对于每个位置 `(i, j)`,我们检查 `s1[i -1]` 和 `s2[j -1]` 是否相等。如果它们相等,则 `dp[i][j]` 的值是 `dp[i -1][j -1]` 的值加一。否则,我们取 `dp[i -1][j]` 和 `dp[i][j -1]` 中较大的值。
* 最后,我们从 `dp` 数组中重构了 LCS。我们从 `(m, n)` 开始,检查当前位置的值。如果它等于前一个位置的值加一,则将该值添加到 LCS 中,并移动到上一个位置。否则,我们移动到下一个位置。
### **1035. 不相交的线**
#### **问题描述**
给定 `n` 个不相交的线段,每个线段由两个坐标 `(x1, y1)` 和 `(x2, y2)` 定义。请找出这些线段中最多有多少条可以同时画在同一张纸上。
#### **示例**
* 输入:`n =4`
输出: `4`
#### **解决方案**
我们可以使用贪婪算法来解决这个问题。首先,我们需要定义一个函数 `getMaxVal`,该函数返回给定线段的最大值和最小值。
def getMaxVal(x1, y1, x2, y2): return max(x1, x2), min(y1, y2)
然后,我们可以使用贪婪算法来找到不相交的线段的数量。我们首先将所有线段的最大值和最小值存储在一个列表中。
def getLines(n): lines = [] for i in range(1, n +1): x1, y1 =2 * i -3,0 x2, y2 =2 * i -1,4 maxVal, minVal = getMaxVal(x1, y1, x2, y2) lines.append((maxVal, minVal)) return lines
接下来,我们可以使用贪婺算法来找到不相交的线段的数量。我们首先将所有线段的最大值和最小值存储在一个列表中。
def getNonIntersectingLines(lines): nonIntersectingLines = [] for i in range(len(lines)): count =1 for j in range(i +1, len(lines)): if lines[i][0] > lines[j][1]: count +=1 nonIntersectingLines.append(count) return max(nonIntersectingLines)
最后,我们可以使用上述函数来找到不相交的线段的数量。
def findNonIntersectingLines(n): lines = getLines(n) return getNonIntersectingLines(lines)
#### **注释**
* 我们首先定义了一个函数 `getMaxVal`,该函数返回给定线段的最大值和最小值。
* 然后,我们使用贪婺算法来找到不相交的线段的数量。我们首先将所有线段的最大值和最小值存储在一个列表中。
* 接下来,我们使用贪婺算法来找到不相交的线段的数量。我们首先将所有线段的最大值和最小值存储在一个列表中。
* 最后,我们使用上述函数来找到不相交的线段的数量。
### **53. 最大子序和**
#### **问题描述**
给定一个整数数组 `nums`,请找出该数组中最大子序列和。
#### **示例**
* 输入:`[-2,1,-3,4,-1,2,1,-5,4]`
输出: `6`
#### **解决方案**
我们可以使用动态规划来解决这个问题。首先,我们需要定义一个数组 `dp`,其中 `dp[i]` 表示 `nums[0..i-1]` 的最大子序列和。
def maxSubarraySum(nums): dp = [0] * len(nums) dp[0] = nums[0] for i in range(1, len(nums)): if nums[i] >0: dp[i] = max(dp[i -1], nums[i]) else: dp[i] = dp[i -1] return max(dp)
#### **注释**
* 我们首先定义了一个数组 `dp`,其中 `dp[i]` 表示 `nums[0..i-1]` 的最大子序列和。
* 然后,我们将 `dp[0]` 初始化为 `nums[0]`。
* 接下来,我们遍历 `nums`,对于每个位置 `i`,我们检查 `nums[i]` 是否大于零。如果它是,则 `dp[i]` 的值是 `max(dp[i -1], nums[i])`。否则,`dp[i]` 的值保持不变。
* 最后,我们返回 `dp` 中的最大值。
#### **时间复杂度**
* 时间复杂度为 O(n),其中 n 是数组长度。
#### **空间复杂度**
* 空间复杂度为 O(n),其中 n 是数组长度。