- 基础问题
最长公共子序列
- 2025-8-28 21:44:53 @
题意概括
给定两个字符串(或序列) 和 ,找到它们的最长公共子序列(Longest Common Subsequence, LCS)的长度。子序列是指从原序列中删除零个或多个元素后,其余元素保持原有相对顺序得到的序列。
数据范围:
- 两个字符串的长度 均满足 。
- 字符串由小写英文字母构成。
基础知识
最长公共子序列 (LCS)
LCS 问题是动态规划的经典应用之一。
-
状态定义: 我们定义 表示第一个字符串 的前 个字符(即子串 )与第二个字符串 的前 个字符(即子串 )的最长公共子序列的长度。
-
状态转移方程: 在计算 时,我们主要关注 的第 个字符 和 的第 个字符 :
-
情况一: 如果这两个字符相等,那么这个字符必然可以作为 和 的一个公共子序列的末尾元素。因此,LCS 的长度就等于 和 的 LCS 长度加一。
-
情况二: 如果这两个字符不相等,那么它们不可能同时作为 LCS 的末尾元素。此时,LCS 的长度取决于两种情况中的较大者:
- 和 的 LCS 长度(即 )。
- 和 的 LCS 长度(即 )。
-
-
初始化: 且 对于所有的 成立,因为任何字符串与空字符串的 LCS 长度都为 0。
-
最终答案: 两个完整字符串的 LCS 长度即为 。
复杂度分析:
- 时间复杂度: ,因为需要填充一个 大小的 DP 表。
- 空间复杂度: ,用于存储 DP 表。
样例
样例 1
- 输入:
abcde ace
- 输出:
3
- 说明: 最长公共子序列是 "ace"。
样例 2
- 输入:
banana atana
- 输出:
4
- 说明: 最长公共子序列是 "aana"。
C++ 代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1005;
string a, b;
int dp[N][N]; // dp[i][j] 表示 a 的前 i 个字符和 b 的前 j 个字符的 LCS 长度
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> a >> b;
int n = a.length();
int m = b.length();
// 为了方便处理边界,我们将字符串看作 1-indexed
// dp 数组已默认初始化为 0,满足边界条件
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i - 1] == b[j - 1]) {
// 字符匹配,LCS 长度加一
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
// 字符不匹配,取两种情况的最大值
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
cout << dp[n][m] << endl;
return 0;
}
0 条评论
目前还没有评论...