题目 : https://www.luogu.com.cn/problem/P1439
最长公共子序列(简化版)
字串的长度 n<=1000
时间复杂度高,大概是O(n2)
使用二维数组进行状态转移,有一个固定的公式。
(dp[i][j]=egin{cases} max(dp[i-1][j], do[i][j-1]) + 1 quad s[i] =t[j]\\ max(dp[i-1][j], do[i][j-1]) quad s[i] !=t[j]end{cases})
#include <cstdio>
using namespace std;
const int MAXN =1e3+5;
int a[MAXN],b[MAXN];
int dp[MAXN][MAXN];
int max(int a,int b){
return a>b?a:b;
}
int main(){
int N;
scanf("%d",&N);
for(int i=1;i<=N;i++)
scanf("%d",&a[i]);
for(int i=1;i<=N;i++)
scanf("%d",&b[i]);
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
if(a[i]==b[j]){
dp[i][j]++;
}
}
}
// for(int i=1;i<=N;i++){
// for(int j=1;j<=N;j++)
// printf("%d ",dp[i][j]);
// printf("
");
// }
printf("%d
",dp[N][N]);
return 0;
}
最长公共子序列(进阶版)
n<=100000
题解 : 将一个序列离散化,离散化只有变成1 2 3 4 5 ......
则要求最长公共子序列就会转化为求最长上升子序列,按照进阶版的二分进行查找添加,更新值就会成为结果。注意题目中的1-n的排列。
#include <map>
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
const int MAXN = 1e5+5;
int a[MAXN],b[MAXN];
int main(){
int N;
scanf("%d",&N);
map<int,int>m;
m.clear();
for(int i=0;i<N;i++){
scanf("%d",&a[i]);
m[a[i]]=i+1;
}
for(int i=0;i<N;i++){
scanf("%d",&b[i]);
b[i]=m[b[i]];
}
vector<int>v;
v.push_back(b[0]);
for(int i=1;i<N;i++){
int l=0,r=v.size();
if(b[i]>v[v.size()-1])
v.push_back(b[i]);
else{
while(l<r){
int mid=(l+r)/2;
if(b[i]>v[mid])l=mid+1;
else r=mid;
}
v[l]=b[i];
}
}
printf("%d
",v.size());
return 0;
}