2.9总结

用f[i][j]来表示将a的前i个字符操作成b的前[j]个字符的最少操作次数。

对于f[i][j]:我们之前已有以下数据

如果a[i]=b[j]:那么我们在f[i-1][j-1]的基础上不需要做任何操作即可完成。步数=f[i-1][j-1].

如果a[i]!=b[j]:

那么可以在f[i-1][j-1]的基础上把a[i]修改为b[j],步数f[i-1][j-1]+1;

或者在f[i-1][j]的基础上将a[i]删除,步数f[i-1][j]+1;

或者在f[i][j-1]的基础添加b[j],步数f[i][j-1]+1;

在所有步数中选出最小值即可。

#include<stdio.h>
#include<string.h>
int main()
{
    char a[2005],b[2005];
    int la,lb,f[2005][2005];
    scanf("%s",a+1);
    la=strlen(a+1);
    scanf("%s",b+1);
    lb=strlen(b+1);
    for(int i=1;i<=la;i++) f[i][0]=i;
    for(int i=0;i<=lb;i++) f[0][i]=i;
    for(int i=1;i<=la;i++)
    {
        for(int j=1;j<=lb;j++)
        {
            int min=99999;
            if(a[i]==b[j])
            {
                f[i][j]=f[i-1][j-1];
                continue;
            }
            if(min>f[i-1][j]+1) min=f[i-1][j]+1;
            if(min>f[i][j-1]+1) min=f[i][j-1]+1;
            if(min>f[i-1][j-1]+1) min=f[i-1][j-1]+1;
            f[i][j]=min;
        }
    }
    printf("%d",f[la][lb]);
    return 0;
}

要满足序列是某序列的子集,这个子序列的元素应该在全序列中的位置(下标)依次递增,那么要找出a,b的公共子序列,其中所有元素在a,b中的下标一次增大。也就是说,要从b中找出a的子序列,只要满足其在a中的下标递增即可。所以我们记录b中元素在a中出现的下标。我们用a[i]表示数字i在a中的位置,a中的递增序列即为公共子序列,接下来便求a的最长增序列。

用f[i]表示前[i]个数字最大增序列的最后一个数,即最大数.对于某一个,如果a[i]>a[i-1],那么可以形成新的更长的增序列。否则,我们需要找到一个比a[i]小的最大的数,再将其a[i]排在其后面又得到新序列,

#include<stdio.h>
int main()
{
    int a[100005],f[100005],map[100005],n,num,l,r,mid,len=1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num);
        a[num]=i;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num);
        map[i]=a[num];
        f[i]=999999;
    }
    f[1]=map[1];
    for(int i=2;i<=n;i++)
    {
        l=1;r=len;
        if(map[i]>f[len])
        {
            len++;
            f[len]=map[i];
        }
        else
        {
            while(l<r)
            {
                mid=(l+r)/2;
                if(map[i]<f[mid]) r=mid;
                else l=mid+1;
            }
            f[l]=map[i]<f[l]?map[i]:f[l];
        }
    }
    printf("%d",len);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值