一 最长上升子序列(LIS)
【题目描述】
给定N个数,求这N个数的最长上升子序列的长度。
【样例输入】
7
2 5 3 4 1 7 6
【样例输出】
4
分析:
维护一个子序列,遍历母序列,子序列的第一个元素是母序列的第一个元素,然后依次比较母序列的每个元素A和子序列的最后一个元素B的大小关系,如果A>B,那么将A放在子序列的后面,否则,在子序列中找到第一个大于或等于A的元素,将其更换为A(这里用的是二分查找),时间复杂度为O(n*logn)
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 5;
int a[maxn];
int dp[maxn];
int main(){
int n;
cin>>n;
for(int i = 0 ; i < n ; i ++ ) cin>>a[i];
dp[0] = a[0];
int k = 1;
for(int i = 1 ; i < n ; i ++ ){
if(a[i]>dp[k-1]) dp[k++] = a[i];
else{
int p = lower_bound(a,a+n,a[i]) - a ;
dp[p] = a[i] ;
}
}
cout<<k<<endl;
}
二 最长公共子序列(LCS)
【题目描述】
给定两个字符串 s , t ,求出这两个字符串最长的公共子序列的长度。
【样例输入】
n = 4
m = 4
s = "abcd"
t = "becd"
【样例输出】
3("bcd")
分析:
将dp[i][j]定义为 s1....si 和t1....tj 的对应LCS的长度
由此,s1....si+1和t1....tj+1对应的公共子序列可能为
1)当 si+1 = tj+1 时 在其现在的LCS的末尾加上 si+1;
2)s1....si 和 t1....tj+1 的公共子序列
3)s1....si+1 和 t1....tj 的公共子序列
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 5;
char s[maxn],t[maxn];
int n,m;
int dp[maxn+1][maxn+1];
int main(){
cin>>n>>m;
cin>>s>>t;
for(int i = 0 ; i < n ; i ++ ){
for(int j = 0 ; j < m ; j ++ ){
if(s[i]==t[j])
dp[i+1][j+1] = dp[i][j] + 1;
else
dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j]);
}
}
cout<<dp[n][m]<<endl;
}