AcWing 272. 最长公共上升子序列

简介: AcWing 272. 最长公共上升子序列

AcWing 272. 最长公共上升子序列

本题链接:AcWing 272. 最长公共上升子序列

本博客给出本题截图

image.png

AC代码

代码解释f[i][j]代表所有在a[1 ~n]b[1 ~ n]中都出现过,并且以b[j]结尾的公共上升子序列的最大值的集合

如果不包含a[i]的话那么

f[i][j] = f[i - 1][j];

如果包含a[i]的话,那么我们现在的公共上升子序列必然最后一位是a[i] (b[j]),那么我们开始根据倒数第二位去继续划分,进行状态转移,那么我们假设这个子序列的倒数第二位是b[k] (k < j),当k == 0时证明没有倒数第二位,即当前子序列只有一个数,即maxv = 1,然后k从 1 开始遍历到 j - 1,注意在遍历的过程中,只有满足 b[k] < b[j]才可以更新maxv

if (a[i] == b[j])
{
  int maxv = 1;
  for (int k = 1; k < j; k ++ )
    if (b[k] < b[j]) 
      maxv = max(maxv, f[i - 1][k] + 1);
  f[i][j] = max(f[i][j], maxv);
}

TLE版

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3010;
int a[N], b[N], f[N][N];
int main()
{
    int n;
    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];
            if (a[i] == b[j])
            {
                int maxv = 1;
                for (int k = 1; k < j; k ++ )
                    if (b[k] < b[j]) 
                        maxv = max(maxv, f[i - 1][k] + 1);
                f[i][j] = max(f[i][j], maxv);
            }
        }
    int res = 0;
    for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);
    cout << res << endl;
    return 0;
}

代码优化:三重循环,TLE 也不太意外,如何去优化呢?从第三重循环去下手,我们发现,对于我们遍历的每一个j,第三重循环都会重新遍历一遍1 ~ j - 1,这样显然是有很多重复在其中的,我们如果可以每次都把1 ~ j - 1中的最大值给存储起来,那么当我们j ++后,下一次该遍历1 ~ j的时候,只需要用这个最大值再去和j去比较即可,故我们把maxv放到一重循环中,然后来观察那个TLE代码:

if (a[i] == b[j])
{
  int maxv = 1;
  for (int k = 1; k < j; k ++ )
    if (b[k] < b[j]) 
      maxv = max(maxv, f[i - 1][k] + 1);
  f[i][j] = max(f[i][j], maxv);
}

在这个代码中if (b[k] < b[j])可以替换为if (b[k] < a[i]),因为大前提是if (a[i] == b[j]),那么这个第三重的for循环就可以理解成在前j - 1中找到所有b[k] < a[i]的然后去更新,故当我们去掉第三重循环后可优化为:

if (a[i] > b[j]) maxv = max(maxv, f[i - 1][j] + 1);

AC代码

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3010;
int a[N], b[N], f[N][N];
int main()
{
    int n;
    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 (a[i] > b[j]) maxv = max(maxv, f[i - 1][j] + 1);
        }
    }
    int res = 0;
    for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);
    cout << res << endl;
    return 0;
}


目录
相关文章
|
7月前
leetcode-521:最长特殊序列 Ⅰ
leetcode-521:最长特殊序列 Ⅰ
47 0
【动态规划刷题 14】最长递增子序列的个数&& 最长数对链
【动态规划刷题 14】最长递增子序列的个数&& 最长数对链
|
2月前
acwing 895 最长上升子序列1
acwing 895 最长上升子序列1
30 3
|
2月前
acwing 896 最长上升子序列II
acwing 896 最长上升子序列II
27 2
|
2月前
acwing272. 最长公共上升子序列
acwing272. 最长公共上升子序列
30 0
|
7月前
代码随想录 Day44 动规12 LeetCode T300 最长递增子序列 T674 最长连续递增序列 T718 最长重复子数组
代码随想录 Day44 动规12 LeetCode T300 最长递增子序列 T674 最长连续递增序列 T718 最长重复子数组
66 0
|
算法
代码随想录算法训练营第五十二天 | LeetCode 300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
代码随想录算法训练营第五十二天 | LeetCode 300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
51 1
算法修炼Day57|647. 回文子串 ● 516.最长回文子序列
算法修炼Day57|647. 回文子串 ● 516.最长回文子序列
|
算法 C++
每日算法系列【LeetCode 329】矩阵中的最长递增路径
每日算法系列【LeetCode 329】矩阵中的最长递增路径
代码随想录刷题|LeetCode 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组
代码随想录刷题|LeetCode 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组
代码随想录刷题|LeetCode 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组