一: 状态表示
f[i][j] ;
第一个序列前 i 个字母,与第二个序列前 j 个字母,为确定公共上升子序列的结尾数我们规定以第二个序列的第 j 个字母为结尾;
第一个序列前 i 个字母,与第二个序列前 j 个字母,并且以第二个子序列第 j 个数结尾的公共上升子序列
二 :状态计算
划分为包括第 i 个数与不包括第 i 个数的两个集合
对于不包括第 i 个数的f[i][j] = f[i - 1][j];
第二种状态的判断依据为 a[i] == b[j]
对于包括第 i 个数的f[i][j] = max(f[i][j], f[i] [1 ~ j - 1] + 1);
找出前f[i][1 ~ j - 1] 中公共上升子序列最大值
代码一 ,时间复杂度n^3 很明显该代码是很容易超时的,因为必须枚举到a,b两个数组,所以可以把时间复杂度优化到 n^2;
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3010;
int a[N],b[N],f[N][N];
int n;
int main()
{
cin >> n;
for (int i = 1;i <= n;i ++ ) cin >> a[i];
for (int i = 1;i <= n;i ++ ) cin >> b[i];
for (int i = 1;i <= n;i ++ )
{
for (int j = 1;j <= n;j ++ )
{
f[i][j] = f[i - 1][j];//默认等于不包括 a[i]
if (a[i] == b[j])
{
f[i][j] = max(f[i][j],1);
for (int k = 1;k < j;k ++ )
{
if (b[k] < b[j])
f[i][j] = max(f[i][j],f[i - 1][k] + 1);
}
}
}
}
int res = 0;
for (int i = 1;i <= n;i ++ ) res = max(res,f[n][i]);
cout << res << endl;
return 0;
}
写错了下面才是对的
代码二(优化) 时间复杂度n^2
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3010;
int a[N],b[N],f[N][N];
int n;
int main()
{
cin >> n;
for (int i = 1;i <= n;i ++ ) cin >> a[i];
for (int i = 1;i <= n;i ++ ) cin >> b[i];
for (int i = 1;i <= n;i ++ )
{
int maxv = 1;
for (int j = 1;j <= n;j ++ )
{
f[i][j] = f[i - 1][j];
if (a[i] == b[j]) f[i][j] = max(f[i][j],maxv);
if (b[j] < a[i]) maxv = max(maxv,f[i][j] + 1);//此步等于朴素版的b[k] < b[j]==a[i] ;的判断,把该值存储
}
}
int res = 0;
for (int i = 1;i <= n;i ++ ) res = max(res,f[n][i]);
cout << res << endl;
return 0;
}