LCS/LIS/LCIS

本文详细介绍了LCS(最长公共子序列)和LCIS(最长公共上升子序列)的算法思想。对于LCS,通过动态规划实现O(n^2)的时间复杂度,并解释了状态转移方程。而对于LCIS,同样采用动态规划,讨论了如何在O(n^2)时间内找到最长公共上升子序列,并给出了相应的算法和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LCS

这里仅仅记录一下LCS算法的思路:典型的DP,空间换时间

step 1: 先比较两个子串的对应位是否相同,如果相同,则b[i][j]='\',并且c[i][j]=c[i-1][j-1]+1,否则转向step2

step 2:如果上角的值>=左角的值,那么将上角的值赋给c[i][j],同时b[i][j]箭头指向大值(指向上角)。如果上角的值<左角的值,箭头指向大值(指向左),左角的值赋给c[i][j]


实例:

求X=<A,B,C,B,D,A,B>和Y=<B,D,C,A,B,A>的最长公共子序列,在第一行中,第一行为A和第4列第6列的值A相同,

于是b[][]中存储的箭头指向上对角。同时c[][]的值为上对角的值+1。如果X,Y对应的相应位不同,那么b[][]的箭头总是

指向大值,如果两值相等,则指向上面那一个。遍历完之后,就可以得出b[][]和c[][],就能确定LCS。

要点:

1.b[i][j]存放的是箭头,若Xi==Yi,则箭头指向对角线b[i-1][j-1],否则箭头总是指向大值,

若上值b[i-1][j]和左值b[i][j-1]相等,优先指向上值。
2.c[i][j]存放的是数值,若Xi==Yi,则c[i][j]值为上对角值c[i-1][j-1]+1,否则c[i][j]=max(c[i][j-1],c[i-1][j])

代码:

#include<iostream>
using namespace std;
#define M 7
#define N 6
int b[M+1][N+1]={0};//保存箭头
int c[M+1][N+1]={0};//保存值

void Lcs_Length(char* X,char* Y)
{
	int i,j;
	for(i=1;i<=M;i++)//第0列置0
		c[i][0]=0;
	for(j=0;j<=N;j++)
		c[0][j]=0;  //第0行置0
	for(i=1;i<=M;i++)
	{
		for(j=1;j<=N;j++)
		{
			if(X[i]==Y[j])//比较两个字串对应位,如果相等,则=对角+1
			{
				c[i][j]=c[i-1][j-1]+1;
				b[i][j]=1;//1代表↖ 
			}
			else if(c[i-1][j]>=c[i][j-1])//如果上面值>=下面值
			{
				c[i][j]=c[i-1][j];//c[i][j]=大值
				b[i][j]=2;//2代表↑
			}
			else 
			{
				c[i][j]=c[i][j-1];//赋的总是大值,箭头总是指向大值
				b[i][j]=3;//3代表←
			}
		}
	}
}
void Print_Lcs(char* X,int i,int j)
{
	if(i==0 || j==0)
		return ;
	if(b[i][j]==1)
	{
		Print_Lcs(X,i-1,j-1);
		cout<<X[i]<<' ';//只需输出↖对应的值
	}
	else if(b[i][j]==2)
		Print_Lcs(X,i-1,j);
	else Print_Lcs(X,i,j-1);
}
void main()
{
	 char  X[M+1] = {'0','A','B','C','B','D','A','B'};  
	 char  Y[N+1] = {'0','B','D','C','A','B','A'};  
    Lcs_Length(X, Y);  
    Print_Lcs(X, M, N);  
	cout<<endl;
	for(int i=0;i<=M;i++)
	{
		for(int j=0;j<=N;j++)
		{
			cout<<c[i][j]<<' ';
		}
		cout<<endl;
	}
	cout<<endl;
	for(int i=0;i<=M;i++)
	{
		for(int j=0;j<=N;j++)
		{
			switch(b[i][j])
			{
			case 0:
				{
					cout<<b[i][j]<<"  ";
					break;
				}
			case 1:
				{
					cout<<"↖"<<' ';
					break;
				}
			case 2:
				{
					cout<<"↑"<<' ';
					break;
				}
			case 3:
				{
					cout<<"←"<<' ';
					break;
				}
			}
		}
		cout<<endl;
	}
}

LCIS

以下来自百度文库:

最长公共上升子序列(LCIS)的O(n^2)算法

预备知识:动态规划的基本思想,LCS,LIS。

问题:字符串a,字符串b,求a和b的LCIS(最长公共上升子序列)。

首先我们可以看到,这个问题具有相当多的重叠子问题。于是我们想到用DP搞。DP的首要任务是什么?定义状态。

1定义状态F[i][j]表示以a串的前i个字符b串的前j个字符且以b[j]为结尾构成的LCIS的长度。

为什么是这个而不是其他的状态定义?最重要的原因是我只会这个,还有一个原因是我知道这个定义能搞到平方的算

法。而我这只会这个的原因是,这个状态定义实在是太好用了。这一点我后面再说。

我们来考察一下这个这个状态。思考这个状态能转移到哪些状态似乎有些棘手,如果把思路逆转一下,考察这个状态

的最优值依赖于哪些状态,就容易许多了。这个状态依赖于哪些状态呢?

首先,在a[i]!=b[j]的时候有F[i][j]=F[i-1][j]。为什么呢?因为F[i][j]是以b[j]为结尾的LCIS,如果F[i][j]>0那么就说明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Raise

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值