LCIS 最长上升公共子序列问题

首先点名一个串叫 L1,另一个叫L2。

明显的是一个DP,那么我们来探讨下如何求得答案。

朴素的算法

首先我们定义状态$dp[ i ][ j ]$表示L1中前i个与L2中前j个的最长公共上升子序列。

最外层枚举i,第二层枚举j,那么L1[i]和L2[j]要么相等,要么不相等,分情况讨论。

■ L1[i]=L2[j] 那么我们以当前L1[i]的大小作为某个公共上升子序列的结尾元素,所以我们就需要向前找比这个结尾元素小的元素来接头,就需要找到dp[i-1][k] $(k<j&&a[k]<a[j])$中的最长的公共上升子序列的长度,然后其数列长度+1,就是现在dp[i][j]的值。

■ L[1]!=L2[j]那么这时候我们则需要继承前边最长的序列长度$dp[i][j]=max(dp[i-1][1->j-1])$.

这样的时间复杂度$O(n^2 \times m)$,空间复杂度$O(n \times m)$,比较朴素的一中做法。

代码自行脑补吧。。。。

 

优化

我们来优化一下上边的算法。

我们每个数在计算的时候,这一行前边的数我们已经都计算过了,在这之间我们完全可以用maxn记录一下最大值,避免再去循环枚举k,直接用maxn就好了。

时间复杂度$O(n \times m)$

void LCIS(){
    memset(F,0,sizeof(F));
    for(int i=1;i<=n;i++){
        LL maxn = 0;
        for(int j=1;j<=m;j++){
            F[i][j] = F[i-1][j];
            if(a[i]>b[j] && maxn < F[i-1][j]) maxn = F[i-1][j];
            if(a[i] == b[j]) 
            F[i][j] = maxn+1;
        }
    }
    LL maxn = 0;
    for(int j=1;j<=m;j++){
        if(maxn < F[n][j]) maxn = F[n][j];
    }
    printf("%lld\n",maxn);
}

空间复杂的也可以通过压维进行优化。

对于每次dp[i][j]的改变我们只需要dp[i-1][1->j-1]中的最大值,压维以后,我们只需要dp[i][1->j-1]中的最大值,同样maxn记录就好了。

你可能会问:

每次我们查询后边的都会用到前边的,前边的改变后对后边的不会有影响么?

不会,因为我们只需要最大值,在这个数改变之前,进行最大值的替换,当它改变后对后边计算没有任何影响。

#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int T,n,m,f[100006],a[100006],b[100006],ans;
int max(int a,int b){ return a>b?a:b; }
int main()
{
    freopen("codes.in","r",stdin);
    freopen("codes.out","w",stdout);
    scanf("%d",&T);
    while(T--)
    {
        ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)scanf("%d",&b[i]);
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++)
        {
            int maxn=0;
            for(int j=1;j<=m;j++)
            {
                if(a[i]>b[j])maxn=max(maxn,f[j]);
                if(a[i]==b[j])f[j]=maxn+1;
                ans=max(ans,f[j]);
            }
        }
        printf("%d\n",ans);
    }
    fclose(stdin);fclose(stdout);
}

 

posted @ 2018-09-03 22:19  Manjusaka丶梦寒  阅读(369)  评论(1编辑  收藏  举报