一、【模板】最长公共子序列


1.思路
刚开始写这个题的时候,一看,嗯,最长子序列模板,嗯,去搜了模板和思路,嗯,打上模板,嗯,MLE了,嗯,10的5次方,嗯,坑爹呢!!
不过还是得讲一下这个最长子序列的模板,首先我们把最长子序列称为lcs,第一个串为a{a1,a2,a3.......an},第二个串b{b1,b2,b3.......bm}, 子序串z{z1,z2,z3......zk},那么这个lcs有以下特性:
①如果an=bn,那么zk=an=bm,z-1是a-1和b-1的lcs
②如果an!=bm,且zk!=an,那么z是a-1和b的lcs
③如果an!=bm,且zk!=am,那么z是a和b-1的lcs
那么该怎么实现这个过程呢
设二维数组c,其中 从c[i][j]代表当前最长子序列

就以本题例子为例,那么在二维数组里面就是以此显示

那么代码实现为
#include<stdio.h>
int n;
int a[100001],b[100001],dp[100001][100001];
int max(int x,int y)
{
if(x>y)return x;
else return y;
}
int main()
{
int i,j,maxx=0;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)scanf("%d",&b[i]);
for(i=0;i<=n;i++) //初始化
{
dp[i][0]=0;
dp[0][i]=0;
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(a[i]==b[j])dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
maxx=max(maxx,dp[i][j]);
}
}
printf("%d",maxx);
return 0;
}
关于这个题,就是求最长上升子序,将a数组的重新定义,就相当于把a数组重新定义为1,2,3,4,5,那么b数组就变为了3,2,1,4,5
2.代码实现
#include<stdio.h>
int n;
int a[100001],b[100001],dp[100001],f[100001];
int min(int x,int y)
{
if(y>x)return x;
else return y;
}
int main()
{
int i,j,len=0,left,right,mid;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
dp[a[i]]=i; //重新定义
}
for(i=1;i<=n;i++)
{
f[i]=0x7fffffff; //初始化
scanf("%d",&b[i]);
}
f[0]=0;
for(i=1;i<=n;i++)
{
left=0;
right=len;
if(dp[b[i]]>f[len])f[++len]=dp[b[i]];
else
{
while(left<right)
{
mid=(left+right)/2;
if(f[mid]>dp[b[i]])right=mid;
else left=mid+1;
}
f[left]=min(dp[b[i]],f[left]);
}
}
printf("%d",len);
return 0;
}
二、编辑距离


1.思路
由此题我们可以知道,针对于字符串a,我们有“删除,添加,替换,不变”这四种情况,那么我们该怎样用利用这四种子问题呢?
假设dp[i][j]表示要操作几步,i表示前i个字母,j表示前j个字母
1.当要删除的时候,dp[i][j]=dp[i-1][j]+1
2.当要添加的时候,dp[i][j]=dp[i][j-1]+1
3.当要替换的时候,dp[i][j]=dp[i-1][j-1]+1
4.当不变的时候,dp[i][j]=dp[i-1][j-1]
2.代码实现
#include<stdio.h>
#include<string.h>
int dp[2001][2001];
char a[2001],b[2001];
int min(int x,int y)
{
if(x>y)return y;
else return x;
}
int main()
{
int i,j,k,L1,L2;
scanf("%s %s",a+1,b+1);
L1=strlen(a+1);
L2=strlen(b+1);
for(i=0;i<=L1;i++)dp[i][0]=i;
for(i=0;i<=L2;i++)dp[0][i]=i;
for(i=1;i<=L1;i++)
{
for(j=1;j<=L2;j++)
{
k=1; //k表示替换
if(a[i]==b[j])k=0; //不变的时候,k=0,表示不变
dp[i][j]=min(min(dp[i-1][j]+1,dp[i][j-1]+1),dp[i-1][j-1]+k);
}
}
printf("%d",dp[L1][L2]);
return 0;
}