【最长上升子序列】、【最长公共子序列】、【最长公共上升子序列】
- 最长上升子序列
- f[i] 表示以i结尾的最长子序列
 
 
- 最长公共子序列
- f[i][j] 表示 a前i 和 b前j个 最长公共长度
 
 
- 最长公共上升子序列
- f[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]结尾的公共上升子序列的集合
 
 
- 最长公共子串
 
最长上升子序列

f[i] 表示以i结尾的最长子序列
由于我们遍历到i时候
 我们需要比较i前面的数据
我们发现如果i 大于 j
那么i就可以拼接在 j 后面
如果f[j] 就是j最长的了
 那就
 f[i] = f[j] + 1的长度
 所以
 f[i] 表示以i结尾的最长子序列
#include<iostream>
using namespace std;
const int N = 1100;
int a[N];
int f[N];
int res = 0;
int n;
int main()
{
    cin >> n;
    
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    a[0] = -0x3f3f3f3f;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j <= i ; j++)
        {
            if(a[j] < a[i])
                f[i] = max(f[i],f[j]+1);
            res = max(res,f[i]);
        }
    }
    
    cout << res;
    
    return 0;
}
最长公共子序列

f[i][j] 表示 a前i 和 b前j个 最长公共长度
#include<iostream>
using namespace std;
const int N = 1010;
int f[N][N];
char a[N],b[N];
int n,m;
int main()
{
    cin >> n >> m;
    cin >> a+1 >> b+1;
    
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            if(a[i]==b[j])
            {
                f[i][j] = f[i-1][j-1]+1;
            }
            else
            {
                f[i][j] = max(f[i-1][j],f[i][j-1]);
            }
        }
    }
    
    cout << f[n][m];
    
    return 0;
}
最长公共上升子序列

f[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]结尾的公共上升子序列的集合
这道题如何理解?
- 记住f[i][j] 表示什么
- 当b的j和i 相等时,我们常规思路是就在b数组中按着第一道题的逻辑 循环遍历之前的值,但是这样是麻烦的。我们需要一种方法,不需要遍历就知道之前的最大值,可以定义一个变量maxv,如果i和j相等,直接等于maxv,如果不相等,那么f[i][j] = f[i-1][j]
- 如果a[i]>b[j]
 那么maxv = max(maxv,f[i-1][j]+1);
maxv的由来
 
#include<iostream>
using namespace std;
const int N = 3030;
int f[N][N];
int a[N],b[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] = maxv;
            }
            if(a[i]>b[j])
                maxv = max(maxv,f[i-1][j]+1);
        }
    }
    
    int ans = 0;
    
    for(int i = 0; i <= n; i++)
    {
        ans = max(f[n][i],ans);
    }
    
    cout << ans;
    
    return 0;
}
最长公共子串

 
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e4 + 10;
char str1[N], str2[N];
int f[N][N];//注意空间限制为256MB,即为2^(8 + 20) = 2^28个字节,
//而一个int型变量占4个字节,那么最多有2^26个int变量,大约为64000000个变量,而此时定义f[N][N]最多有大于1e8个变量,会爆内存
//更何况还有存字符串的空间
int main()
{
    cin >> str1 + 1 >> str2 + 1;    
    int len1 = strlen(str1 + 1), len2 = strlen(str2 + 1);
    int res = 0;
    for (int i = 1; i <= len1; i++)
    {
        //如果最后一位为数字
        if (str1[i] >= '0' && str1[i] <= '9')
        {
            for (int j = 1; j <= len2; j++)
            f[i][j] = 0;
            continue;    
        }
        for (int j = 1; j <= len2; j++)
        {
            //如果最后一位相同且不为数字
            if (str1[i] == str2[j])
                f[i][j] = f[i - 1][j - 1] + 1;
            else f[i][j] = 0;
            res = max(res, f[i][j]);
        }
    }
    cout << res << endl;
    return 0;
}
观察我们在状态计算的过程,第i层循环的值,仅与第i-1层循环的值有关
 我们可以联想到01背包的优化,利用滚动数组来简化空间复杂度
 既然要用到删除一维空间的优化方法,一定要注意:
 二维中:f[i][j] = f[i - 1][j - 1] + 1;
 在一维中,由于f[j] = f[j - 1],小的j已经被更新,那么就不是上一层(i-1)的数据了
 所以必须从大到小遍历
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e4 + 10;
char str1[N], str2[N];
int f[N];
int main()
{
    cin >> str1 + 1 >> str2 + 1;    
    int len1 = strlen(str1 + 1), len2 = strlen(str2 + 1);
    int res = 0;//用于保存答案
    for (int i = 1; i <= len1; i++)
    {
        //如果最后一位为数字
        if (str1[i] >= '0' && str1[i] <= '9')
        {
            for (int j = 1; j <= len2; j++)
            f[j] = 0;
            continue;    
        }
        for (int j = len2; j >= 1; j--)
        {
            //如果最后一位相同且不为数字
            if (str1[i] == str2[j])
                f[j] = f[j - 1] + 1;
            else f[j] = 0;
            res = max(res, f[j]);
        }
    }
    cout << res << endl;
    return 0;
}


















