解法一: f[i][j]表示数列A的前i个和数列B的前j个且以B[i]结尾的最长公共上升子序列
f[i][j]=f[i−1][j] (a[i]≠b[j])
f[i][j]=max(f[i−1][j],f[i−1][t]+1) (a[i]=b[j] 且 1 <= t < j)
#include <iostream> #include <cstring> using namespace std; const int N = 3030; int n; int a[N],b[N]; int f[N][N]; int main () { 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]); int res = 0; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { f[i][j] = f[i-1][j]; if(a[i] == b[j]) { for(int k = j - 1; k >= 1; k--) { if(b[k] < b[j]) { f[i][j] = max(f[i][j],f[i][k]+1); } } } res = max(res,f[i][j]); } } printf("%d ",res); return 0; }
解法二:优化时间复杂度,使用一个变量来维护遍历j之前的最大长度
#include <iostream> #include <cstring> using namespace std; const int N = 3030; int n; int a[N],b[N]; int f[N][N]; int main () { 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]); int res = 0; for(int i = 1; i <= n; i++) { int len = 0; for(int j = 1; j <= n; j++) { f[i][j] = f[i-1][j]; // 分为选i和不选i两种情况,这是不选i的情况 if(a[i] == b[j]) f[i][j] = max(f[i][j],len + 1); // 更新f[i][j] if(a[i] > b[j]) len = max(len,f[i-1][j]); // 更新len res = max(res,f[i][j]); } } printf("%d ",res); return 0; }