commit dadf36d0462caf596d0f5a887859b4d81caa5b3b Author: fly6516 Date: Sun Dec 8 23:11:33 2024 +0800 full file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/Longest-common-subsequence-and-minimum-edit-distance.iml b/.idea/Longest-common-subsequence-and-minimum-edit-distance.iml new file mode 100644 index 0000000..c73e4a2 --- /dev/null +++ b/.idea/Longest-common-subsequence-and-minimum-edit-distance.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..393918c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9f2f7ea --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/LCS.py b/LCS.py new file mode 100644 index 0000000..aba2842 --- /dev/null +++ b/LCS.py @@ -0,0 +1,18 @@ +def longest_common_subsequence(X, Y): + m, n = len(X), len(Y) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for i in range(1, m + 1): + for j in range(1, n + 1): + if X[i - 1] == Y[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[m][n] + + +# 测试 +X = "ABCBDAB" +Y = "BDCAB" +print("LCS Length:", longest_common_subsequence(X, Y)) \ No newline at end of file diff --git a/MED.py b/MED.py new file mode 100644 index 0000000..1c5954d --- /dev/null +++ b/MED.py @@ -0,0 +1,23 @@ +def min_edit_distance(A, B): + m, n = len(A), len(B) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for i in range(m + 1): + dp[i][0] = i + for j in range(n + 1): + dp[0][j] = j + + for i in range(1, m + 1): + for j in range(1, n + 1): + if A[i - 1] == B[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + else: + dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + + return dp[m][n] + + +# 测试 +X = "ABCBDAB" +Y = "BDCAB" +print("Minimum Edit Distance:", min_edit_distance(X, Y)) \ No newline at end of file diff --git a/gpt/concept.md b/gpt/concept.md new file mode 100644 index 0000000..b7be657 --- /dev/null +++ b/gpt/concept.md @@ -0,0 +1,97 @@ +以下是**最长公共子序列(LCS)**和**最小编辑距离**两个算法的基本思想、分析和时间复杂度计算: + +--- + +### **1. 最长公共子序列(LCS)** + +#### **基本思想** +最长公共子序列(LCS)的核心是通过动态规划构建一个二维表,记录两个字符串在不同前缀长度下的公共子序列的最大长度。 + +- 定义状态: + 设 \( dp[i][j] \) 表示字符串 \( X[0:i] \) 和 \( Y[0:j] \) 的最长公共子序列长度。 + +- 状态转移方程: + - 如果 \( X[i-1] == Y[j-1] \):说明当前字符可以纳入公共子序列: + \[ + dp[i][j] = dp[i-1][j-1] + 1 + \] + - 如果 \( X[i-1] \neq Y[j-1] \):说明当前字符不匹配,取之前子问题的最大值: + \[ + dp[i][j] = \max(dp[i-1][j], dp[i][j-1]) + \] + +- 初始条件: + \( dp[i][0] = 0 \) 和 \( dp[0][j] = 0 \),表示任意一个字符串和空串的最长公共子序列长度为 0。 + +- 最终结果: + \( dp[m][n] \) 表示 \( X \) 和 \( Y \) 的最长公共子序列长度,其中 \( m, n \) 分别为 \( X \) 和 \( Y \) 的长度。 + +--- + +#### **算法分析** +- **时间复杂度:** + 构造 \( dp \) 表需要遍历 \( m \times n \) 的网格,其中 \( m \) 和 \( n \) 是两个字符串的长度。因此时间复杂度为 \( O(m \times n) \)。 + +- **空间复杂度:** + 二维表 \( dp \) 的空间复杂度为 \( O(m \times n) \)。若只需要结果,可以优化为一维数组,降低到 \( O(\min(m, n)) \)。 + +--- + +### **2. 最小编辑距离** + +#### **基本思想** +最小编辑距离的目的是计算将字符串 \( A \) 转换为字符串 \( B \) 的最小操作次数(插入、删除、替换)。同样使用动态规划构建一个二维表解决。 + +- 定义状态: + \( dp[i][j] \) 表示将 \( A[0:i] \) 转换为 \( B[0:j] \) 的最小操作次数。 + +- 状态转移方程: + - 如果 \( A[i-1] == B[j-1] \):当前字符无需修改: + \[ + dp[i][j] = dp[i-1][j-1] + \] + - 如果 \( A[i-1] \neq B[j-1] \):需要考虑三种操作: + 1. **插入**:将 \( B[j-1] \) 插入到 \( A[0:i] \) 的末尾: + \[ + dp[i][j] = dp[i][j-1] + 1 + \] + 2. **删除**:删除 \( A[i-1] \): + \[ + dp[i][j] = dp[i-1][j] + 1 + \] + 3. **替换**:将 \( A[i-1] \) 替换为 \( B[j-1] \): + \[ + dp[i][j] = dp[i-1][j-1] + 1 + \] + 取三种操作的最小值: + \[ + dp[i][j] = \min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1 + \] + +- 初始条件: + \( dp[i][0] = i \) 表示将 \( A[0:i] \) 转换为空串需要删除 \( i \) 次, + \( dp[0][j] = j \) 表示将空串转换为 \( B[0:j] \) 需要插入 \( j \) 次。 + +- 最终结果: + \( dp[m][n] \) 表示从 \( A \) 转换为 \( B \) 的最小编辑距离,其中 \( m, n \) 分别为 \( A \) 和 \( B \) 的长度。 + +--- + +#### **算法分析** +- **时间复杂度:** + 与 LCS 相同,需要构造一个 \( m \times n \) 的动态规划表,时间复杂度为 \( O(m \times n) \)。 + +- **空间复杂度:** + 二维表的空间复杂度为 \( O(m \times n) \)。通过滚动数组优化,可以降低到 \( O(\min(m, n)) \)。 + +--- + +### **对比总结** +| **算法** | **时间复杂度** | **空间复杂度** | **核心思想** | +|-------------------|----------------|----------------|--------------------------------------| +| 最长公共子序列 | \( O(m \times n) \) | \( O(m \times n) \) | 构建二维表,利用匹配与不匹配分治求解 | +| 最小编辑距离 | \( O(m \times n) \) | \( O(m \times n) \) | 通过插入、删除、替换操作递归求解 | + +这两个算法均使用动态规划解决,思想和实现类似,但问题背景不同: +- LCS 关注的是**匹配**字符的最大子序列长度。 +- 最小编辑距离则是计算**最少操作次数**。 \ No newline at end of file diff --git a/gpt/main.md b/gpt/main.md new file mode 100644 index 0000000..db2b085 --- /dev/null +++ b/gpt/main.md @@ -0,0 +1,127 @@ +以下是针对实验内容的详细指导和实现建议: + +--- + +### 一、实验目的 +1. **最长公共子序列问题(LCS)** + 理解如何通过动态规划求解两个序列的最长公共子序列,熟悉其算法原理及应用场景。 +2. **最小编辑距离(Levenshtein Distance)** + 掌握最小编辑距离的定义及动态规划实现,理解其在字符串相似度计算中的实际应用。 +3. **动态规划思想** + 学习将复杂问题分解为子问题并通过递推关系逐步求解。 + +--- + +### 二、实验环境 +- **操作系统**:Windows 或 Linux +- **编程语言**:Python 3.x +- **开发工具**:推荐使用 PyCharm、Jupyter Notebook 或 Sublime Text。 + +--- + +### 三、实验内容 +#### **1. 最长公共子序列问题(LCS)** +**基本原理:** +给定两个字符串 \( X \) 和 \( Y \),找到它们的最长公共子序列。动态规划的核心是构建一个二维表 \( dp \),其中 \( dp[i][j] \) 表示 \( X[0:i] \) 和 \( Y[0:j] \) 的最长公共子序列长度。 + +**算法步骤:** +1. 初始化二维表 \( dp \)。 +2. 遍历 \( X \) 和 \( Y \),按以下规则更新 \( dp[i][j] \): + - 若 \( X[i-1] == Y[j-1] \):\( dp[i][j] = dp[i-1][j-1] + 1 \)。 + - 否则 \( dp[i][j] = \max(dp[i-1][j], dp[i][j-1]) \)。 +3. 最后,\( dp[m][n] \) 为结果,其中 \( m, n \) 分别为 \( X \) 和 \( Y \) 的长度。 + +--- + +#### **2. 最小编辑距离** +**基本原理:** +计算将字符串 \( A \) 转换为 \( B \) 的最小操作次数。允许的操作包括插入、删除和替换。 + +**算法步骤:** +1. 构建一个二维表 \( dp \),\( dp[i][j] \) 表示将 \( A[0:i] \) 转换为 \( B[0:j] \) 的最小操作数。 +2. 初始化边界条件: + - \( dp[i][0] = i \)(全删)。 + - \( dp[0][j] = j \)(全插)。 +3. 遍历 \( A \) 和 \( B \),按以下规则更新 \( dp[i][j] \): + - 若 \( A[i-1] == B[j-1] \):\( dp[i][j] = dp[i-1][j-1] \)。 + - 否则 \( dp[i][j] = 1 + \min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) \)。 +4. \( dp[m][n] \) 即为结果,其中 \( m, n \) 分别为 \( A \) 和 \( B \) 的长度。 + +--- + +### 四、实验报告要求 +1. **基本思想说明** + 详细描述 LCS 和最小编辑距离的动态规划思想,包括状态定义和状态转移方程。 +2. **源码** + 提供清晰、注释详尽的 Python 实现。 +3. **算法分析** + - 时间复杂度:分析循环嵌套次数。 + - 空间复杂度:分析二维表的空间占用及优化可能。 +4. **实验结果截图** + 展示控制台输出结果及二维表状态。 + +--- + +### 五、文件提交说明 +1. **文件夹格式:** + 学号+姓名(如 "2024123456张三")。 +2. **文件内容:** + - 实验报告(Word 或 PDF 格式,命名为 `实验报告_学号_姓名`)。 + - 可运行的 Python 源代码文件(如 `lcs_and_edit_distance.py`)。 +3. **上传路径:** + **上电云盘** -> **课程目录** -> **20241202 文件夹**。 + +--- + +以下为代码示例: + +#### **最长公共子序列** +```python +def longest_common_subsequence(X, Y): + m, n = len(X), len(Y) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for i in range(1, m + 1): + for j in range(1, n + 1): + if X[i - 1] == Y[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[m][n] + +# Example +X = "ABCBDAB" +Y = "BDCAB" +print("LCS Length:", longest_common_subsequence(X, Y)) +``` + +#### **最小编辑距离** +```python +def min_edit_distance(A, B): + m, n = len(A), len(B) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for i in range(m + 1): + dp[i][0] = i + for j in range(n + 1): + dp[0][j] = j + + for i in range(1, m + 1): + for j in range(1, n + 1): + if A[i - 1] == B[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + else: + dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + + return dp[m][n] + +# Example +A = "kitten" +B = "sitting" +print("Minimum Edit Distance:", min_edit_distance(A, B)) +``` + +--- + +祝你实验顺利完成!如果有疑问,可以随时联系我。 \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..bc8647f --- /dev/null +++ b/main.py @@ -0,0 +1,21 @@ +from LCS import longest_common_subsequence +from MED import min_edit_distance + +def main(): + print("测试:最长公共子序列和最小编辑距离") + # 输入字符串 + str1 = "ABCBDAB" + str2 = "BDCAB" + + # 测试最长公共子序列 + lcs_length = longest_common_subsequence(str1, str2) + print(f"字符串 '{str1}' 和 '{str2}' 的最长公共子序列长度为:{lcs_length}") + + # 测试最小编辑距离 + edit_distance = min_edit_distance(str1, str2) + print(f"将字符串 '{str1}' 转换为 '{str2}' 的最小编辑距离为:{edit_distance}") + + +# 运行主函数 +if __name__ == "__main__": + main() \ No newline at end of file