现在的位置: 首页 > 综合 > 正文

最长公共子序列

2019年02月09日 ⁄ 综合 ⁄ 共 1800字 ⁄ 字号 评论关闭

适用题型:

Description:

给定两个序列A,B,其长度分别为N,M,现在要你求出这两个序列中最长的一个公共子序列,并使这个子序列递增。比如数列{1,2,0,4,5}和{1,0,4,5,2},其最长公共上升子序列就是{1,4,5},长度为3。

Input:

第一行:一个N;

第二行:N个数,为数列A;

第三行:一个M;

第四行:M个数,为数列B。

Output:

一个数,为最长公共上升子序列的长度。

Sample Input:

5
1 2 0 4 5
5
1 0 4 5 2

Sample Output:

3

主要思路:每次找a[i]==b[j],(i 1-n,j 1-m)然后查找以前的最长的公共上升子序列的长度,更新一下。

最简单的就是设f[i][j]表示以a[i],b[j](这里a[i]==b[j]),结尾的最长公共子序列长度,O(n^2*m^2)。因为每次得往后找另一对i,j。总共找两对i,j。

这里为了简化可以设f[j]表示以b[j]结尾的最长公共子序列,每次找a[i]==b[j],然后比较f[j]与前面出现的最大的f[k]+1比较。这里还有个问题就是得存k的值,而且得注意每次对应一个a[i],应该是k从0开始,j 是从1开始

二维数组的代码:

#include<iostream>
#include<string.h>
#define maxn 100
using namespace std;
void fun(char *A,int m,char *B,int n,int a[][maxn],int b[][maxn])
{
    for(int i=0;i<=m;i++) a[i][0]=0;
    for(int i=0;i<=n;i++) a[0][i]=0;
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(A[i-1]==B[j-1])
            {
                a[i][j]=a[i-1][j-1]+1;
                b[i][j]=0;
            }
            else if(a[i-1][j]>a[i][j-1])
            {
                a[i][j]=a[i-1][j];
                b[i][j]=1;              //行增加,为1
            }
            else
            {
                a[i][j]=a[i][j-1];
                b[i][j]=-1;             //列增加,为-1
            }
        }
    }
}
void print(char *A,int m,char *B,int n,int b[][maxn])
{
    if(m==0||n==0) return ;
    else if(b[m][n]==0)
    {
        print(A,m-1,B,n-1,b);
        cout<<A[m-1];
    }
    else if(b[m][n]==1)
    {
        print(A,m-1,B,n,b);
    }
    else
    {
        print(A,m,B,n-1,b);
    }
}
int main()
{
    char A[maxn],B[maxn];
    int a[maxn][maxn];  //记录每个状态的最大字串长
    int b[maxn][maxn];  //记录前驱
    int m,n;
    cin>>A>>B;
    m=strlen(A),n=strlen(B);
    fun(A,m,B,n,a,b);
    cout<<a[m][n]<<endl;
    print(A,m,B,n,b);
	return 0;
}

代码:

#include<cstdio>
#define MAXN 1000
int n,m;
int a[MAXN],b[MAXN],f[MAXN];
//f[j]表示以j结尾最大值
void dp()
{
    for(int i=1; i<=n; i++)
    {
        int k=0;//设置k从0开始,而i,j都是从1开始的,防止第一组相同的数没有被处理
        for(int j=1; j<=m; j++)
        {
            if(a[i]==b[j])
            {
                if(f[j]<f[k]+1)
                f[j]=f[k]+1;
            }
            if(a[i]>b[j])//下次比较比a[i]小的数的f值,所以每次遇到比a[i]小的数都得更新小比a[i]小的最大f值
            {
                if(f[j]>f[k])
                    k=j;
            }
        }
    }
}
int main()
{
    memset(f,0,sizeof(f));
    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]);
    dp();
    int max=-1;
    for(int i=1; i<=m; i++)
    {
        if(max<f[i])
            max=f[i];
    }
    printf("%d\n",max);
    return 0;
}

【上篇】
【下篇】

抱歉!评论已关闭.