首页 > 其他分享 >最长公共子序列

最长公共子序列

时间:2022-10-06 16:45:54浏览次数:69  
标签:字符 LCS int 公共 序列 最长

最长公共子序列

给定两个长度分别为 \(n,m\) 的序列

试求出最长的公共子序列。

\(\mathcal O(n^2)\) 做法

我们考虑进行动态规划

设 \(f[i][j]\) 表示看完 \(a\) 数组的前 \(i\) 位,\(b\) 数组的前 \(j\) 位的最长公共子序列的长度

那么我们最终的答案就是 \(f[n][m]\)

考虑如何转移,我们分情况来讨论。

当 \(a[i]=b[j]\) 时

\[f[i][j]=f[i-1][j-1]+1 \]

否则

\[f[i][j]=f[i-1][j-1] \]

同时我们考虑继承前面的答案,即

\[f[i][j]=\mathrm max\{ f[i-1][j],f[i][j-1],f[i][j]\} \]

不难发现 \(f[i-1][j-1]\) 一定不会比 \(f[i-1][j]\) 和 \(f[i][j-1]\) 更优,所以我们可以这样来写:

for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		f[i][j]=max(f[i-1][j],f[i][j-1]);
		if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1)
	}
}

还是挺好理解的qwq

但是,我们怎么得到 \(LCS\) 本身而非 \(LCS\) 的长度呢?

也是用一个二维数组 \(b\) 来表示:

在对应字符相等的时候,用↖标记

在 \(p1 >= p2\) 的时候,用↑标记

在 \(p1 < p2\) 的时候,用←标记

伪代码:

若想得到 \(LCS\),则再遍历一次 \(b\) 数组就好了,从最后一个位置开始往前遍历:

如果箭头是↖,则代表这个字符是 \(LCS\) 的一员,存下来后 i--,j--

如果箭头是←,则代表这个字符不是 \(LCS\) 的一员,j--

如果箭头是↑ ,也代表这个字符不是 \(LCS\)的一员,i--

如此直到 \(i = 0\) 或者 \(j = 0\) 时停止,最后存下来的字符就是所有的 \(LCS\) 字符

\(\mathcal O(nlogn)\) 做法

最长上升子序列 \((LIS)\)是可以用来优化最长公共子序列的。

我们通过一个 \(map\) 映射将 \(A\) 序列的数字在 \(B\) 序列中的位置表示出来(如果没有就为0)

因为最长公共子序列是按位向后比对的,所以 \(A\) 序列每个元素在 \(B\) 序列中的位置如果递增,就说明 \(B\) 中的这个数在 \(A\) 中的这个数整体位置偏后,可以考虑纳入 \(LCS\) ——那么就可以转变成求用来记录新的位置的数组中的 \(LIS\)。

\(LIS\) 的 \(\mathcal O(nlogn)\) 算法

#include<bits/stdc++.h>
using namespace std;
const int N=300010;
int a[N],b[N],n,m,ans;
unordered_map<int,int> mp;//映射关系 
int dp[N]; 
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),mp[a[i]]=i;
	for(int i=1;i<=m;i++) scanf("%d",&b[i]),b[i]=mp[b[i]];
	memset(dp,0x3f,sizeof(dp));
	dp[1]=b[1];
	ans=1;
	for(int i=2;i<=m;i++){
		if(b[i]>dp[ans]) {dp[++ans]=b[i];continue;}
		int l=1,r=ans,res=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(dp[mid]<b[i]){
				res=mid;
				l=mid+1;
			}else{ 
				r=mid-1;
			}
		}
		dp[res+1]=min(dp[res+1],b[i]);
	}
	cout<<ans;
	return 0;
}

标签:字符,LCS,int,公共,序列,最长
From: https://www.cnblogs.com/ycw123/p/16757917.html

相关文章

  • 最长上升子序列
    最长上升子序列1、\(n^2\)做法首先我们要知道,对于每一个元素来说,最长上升子序列就是其本身。那我们便可以维护一个\(dp\)数组,使得\(dp[i]\)表示以第\(i\)元素为结......
  • 最长公共上升子序列
    已经快被这玩意搞疯了\(\mathcalO(n^3)\)做法解析:\(f[i][j]\)表示以\(b[j]\)结尾,字符串\(a[i]\)之前的公共上升子序列最大长度;显然:\(f[i−1][j]\leqf[i][j]\)......
  • [答疑]序列图的对象怎么移到下面,像下面这个图
    ​​软件方法(下)分析和设计第8章连载[20210518更新]>>​​lihongwei(627**07)10:17:21潘老师,对象怎么移到下面,像下面这个图:潘加宇(3504847)16:57:36不是移的,消息中有选项:li......
  • [答疑]住出院业务序列图
    ​​软件方法(下)分析和设计第8章连载[20210518更新]>>​​尘语<xnonym***q.com>15:29:51插一个问题2张图,哪个正确,准确潘加宇(3504847)16:11:17图1Browser上有两个Classifie......
  • [答疑]如何在EA的用例序列图中表现出 while() {...}和 do {...} while()
    ​​软件方法(下)分析和设计第8章连载[20210518更新]>>​​593(585**01)2012-09-1415:07:29如何在EA的用例序列图中表现出while(){...}和do{...}while()?张智强@上海......
  • [答疑]饭局的序列图
    ​​软件方法(下)分析和设计第8章连载[20210518更新]>>​​虎人呢(348***359)17:31:53来大家给挑挑毛病虎人呢(348***359)17:36:40虎人呢(348***359)17:36:52我要改进的就......
  • [答疑]老师用评分系统评分的序列图
    ​​[分析方法,伪创新举例]软件方法(下)分析和设计第8章​​单纯な马鹿でありたい(1271***351)14:02:49潘老师麻烦您一下业务建模里的序列图有点思路不太清单纯な马鹿であ......
  • 二叉树两个节点的最近公共祖先问题
    二叉树两个节点的最近公共祖先问题作者:Grey原文地址:博客园:二叉树两个节点的最近公共祖先问题CSDN:二叉树两个节点的最近公共祖先问题题目描述给定一棵二叉树的头节点......
  • css 公共样式base.css
    body,h1,h2,h3,h4,h5,h6,p,ul,ol,li,dl,dt,dd,input{margin:0;padding:0;}*{/*内减模式*/box-sizing:border-box;}body{......
  • 剑☞offer 两个链表的第一个公共节点
    题目描述:给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。题目数据 保证 整个链式结构中不存......