动态规划:求两个字符串的最长公共子序列
问题描述:求两个字符串的最长公共子序列。
思路:使用动态规划的思想,将问题分解为小的子问题。
假设两个字符串序列分别为:X{x0, x1, x2,......, xm}, Y{y0, y1, y2,......, yn}。从后往前比较字符。
如果xm == yn, 则这个字符就是子序列中的一个字符, LCS就是序列{x0, x1, x2,......, xm-1}和{y0, y1, y2,......, yn-1}的LCS加上xm(或yn)。
如果xm != yn, 则求序列{x0, x1, x2,......, xm-1}与{y0, y1, y2,......, yn}的LCS1,{x0, x1, x2,......xm}与{y0, y1, y2......, yn-1}的LCS2,所求的LCS = max{LCS1, LCS2}.
所以建立的动态规划的公式为
注:图片来自《算法导论》
我们可以通过填表格使问题的解决过程更清晰。
用二维数组length来储存LCS的值。
用二维数组state来储存计算LCS的过程
先将表格的第一行第一列全部设为0,这是为了给接下来求LCS的长度做准备。
B | D | C | A | B | A | ||
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | |
A | 0 | ||||||
B | 0 | ||||||
C | 0 | ||||||
B | 0 | ||||||
D | 0 | ||||||
A | 0 | ||||||
B | 0 |
然后比较每一个字符,如果两个字符相同,则在该位置填上其斜上方数值+1(即第二个式子 c[i,j] = c[i-1,j-1]+1);否则填其上方和左方的较大值(即第三个式子 c[i,j] = max{ c[i-1,j], c[i,j-1] }).这个填表的方式是根据公式来的。
表格完成。表格中的最右下角数据即为LCS的长度。
state数组中的值 ,0:斜上方,1:上方,-1:左方。在求length数组的时候,其实state的值就已经确定了,当我们使用第二个式子 c[i,j] = c[i-1,j-1]+1 时,state的值就是0,使用第三个式子 c[i,j] = max{ c[i-1,j], c[i,j-1] } 时,如果c[i-1,j] 较大,state的值就是1,否则是-1.
通过下图可以看出,只有当state的值为0时,该位置的字符才属于LCS (state的值也是根据公式得出的,当该字符属于LCS 时,就要判断{x0, x1, x2,......, xm-1}和{y0, y1, y2,......, yn-1}的LCS,state的值为0,对应的就是行数和列数都减一; 当该字符不属于LCS时,state的值根据max{LCS1, LCS2}来决定,如果LSC1较大,那么state就是-1,对应的就是列数减一,在{x0, x1, x2,......, xm-1}与{y0, y1, y2,......, yn}中求LCS,同理,如果LSC2较大,state就是1,对应的就是行数减一,在{x0, x1, x2,......xm}与{y0, y1, y2......, yn-1}中求LCS).
注:图片来自《算法导论》
从后往前遍历state,当state中的值为0时,说明该字符属于LCS,将其压入栈中,为1,行数减一;为-1,列数减一。最后依次将字符弹出栈,得到的就是两个字符串的LCS.
源代码:
#include<iostream>
#include<stack>
#include<string>
#include<cstring>
using namespace std;/*Function:获得最长子序列及其长度
Param:str1, str2分别表示输入的字符串*/
void getLCS(string &str1, string &str2){int m = str1.length() + 1;int n = str2.length() + 1;int length[m][n]; //该数组用来记录最大子序列的长度int state[m][n]; //该数组存储每次字符串的匹配状态memset( state, 100, sizeof(state) );for(int i=0; i<m; i++){ //初始化第1列length[i][0] = 0;}for(int j=0; j<n; j++){//初始化第1行length[0][j] = 0;}for(int i=1; i<m; i++){for(int j=1; j<n; j++){if(str1[i-1] == str2[j-1]) {length[i][j] = length[i-1][j-1] + 1;state[i][j] = 0;}else if(length[i][j-1] >= length[i-1][j]) {length[i][j] = length[i][j-1];state[i][j] = -1; //列数减一}else {length[i][j] = length[i-1][j];state[i][j] = 1; //行数减一}}}//至此获得了最长子序列的长度,和子序列的匹配情况//打印最长子序列stack<char> lcs;for(int i=m-1, j=n-1; i>=0 && j>=0;){if(state[i][j] == 0){//说明str1的第i个元素和str2的第j个元素相同 lcs.push(str1[i-1]);i--;j--;}else if(state[i][j] == 1){i--; //行数减一}else{j--; //列数减一}}if(lcs.empty()){cout<<"没有公共子序列"<<endl;return ;}cout<<"最长的子序列:";while(!lcs.empty()){cout<<lcs.top();lcs.pop();}cout<<"\n其长度为:"<<length[m-1][n-1];return ;
}int main(){string str1 = {"abcdefghijklmnree"};string str2 = {"cdfgrrze"};cout<<"序列1:"<<str1<<endl;cout<<"序列2:"<<str2<<endl;getLCS(str1,str2);return 0;
}
运行结果:(使用VS Code 编译运行)
初学动态规划,以上只是个人理解,表达的可能不够准确,还望各位大佬指点!!!
动态规划:求两个字符串的最长公共子序列相关推荐
- 两个字符串的最长公共子序列长度_程序员编程算法,解决文本相似度问题的最长公共子序列算法!...
在前面我讲解了如何通过最长公共子串来求解两个文本的相似度问题,但它有一定缺陷,举个例子,看下面的两个字符串 我爱吃小青菜和各种鲜水果. 我很爱吃青菜与各样水果. 上面两个字符串,如果通过计算子串来求相 ...
- 两个字符串的最长公共子序列长度_【面试】动态规划-之最长公共子序列、最长公共子串问题...
先来说明下什么是最长公共子序列,什么是是最长公共子串,举一个实际例子,myblogs与belong,最长公共子序列为blog(myblogs, belong),最长公共子串为lo(myblogs, b ...
- python求最长公共子串_Python-求解两个字符串的最长公共子序列
一.问题描述 给定两个字符串,求解这两个字符串的最长公共子序列(Longest Common Sequence).比如字符串1:BDCABA:字符串2:ABCBDAB.则这两个字符串的最长公共子序列长 ...
- php两个字符串公共,C++_C语言求两个字符串的最长公共子串,本文实例讲述了C语言求两个字 - phpStudy...
C语言求两个字符串的最长公共子串 本文实例讲述了C语言求两个字符串的最长公共子串的方法.分享给大家供大家参考.具体实现方法如下: #include "stdio.h" #inclu ...
- 字符串最长公共子序列python_求解两个字符串的最长公共子序列
一,问题描述 给定两个字符串,求解这两个字符串的最长公共子序列(Longest Common Sequence).比如字符串1:BDCABA:字符串2:ABCBDAB 则这两个字符串的最长公共子序列长 ...
- 两个字符串的最长公共子序列长度_输出两个字符串的最长公共子串和最长公共子序列...
输出两个字符串的最长公共子串和最长公共子序列.求解两个字符串的最长公共子串和最长公共子序列在方法上很接近,都是动态规划.只不过在递推方程上有一些不一样. 求两个字符串的最长公共子串 #include ...
- 求两个字符串的最长公共子串
给出两个字符串,求出两个字符串的最长公共子串 #include<iostream> #include<string> using namespace std; int main ...
- 两个字符串的最长公共子序列长度_求2个字符串的最长公共子序列和最长公共子字符串...
一. 最长公共子序列 定义: 一个数列S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 例如:输入两个字符串BDCABA和 ABCBDA ...
- 求两个字符串的最长公共字串(连续)
题目描述: 输入两个字符串,求其的最长的公共的字串,这与最长公共子序列不一样 输出两字符串的最长公共字串 思路一: 从字符串A开始遍历,同时遍历字符串A,找到第一个与当前字符串A相同的字符,此时记下当 ...
最新文章
- 库克:苹果收取 30% 佣金很合理!
- 20162304 实验三
- 十二天深入理解计算机系统(一)
- Codeforces Round #713 (Div. 3)
- IIS_FastCGI+php5.3+wincache+memcached+ZendLoader
- 基于ArcGIS10.0和Oracle10g的空间数据管理平台(C#开发)-数据库设计
- Java基础总结(一)
- SplitConcatWithAMP----Array转换为String,连接;String转换为Array,切割
- python混合asp_asp后段如何调用python
- 一本关于HTTP的恋爱日记
- Echarts地图详细镇区的划分_echarts乡镇地图,echarts地图街道-算法与数据结构文档
- 如何快速学Web前端开发?JavaScript函数好学吗?
- 文件打印服务器解决方案
- 基于spring boot的Java开源商城系统(附完整版源码)
- Quartz分布式定时任务
- Base64的Woff2字体信息如何转成成文件
- 微信公共号系列---快速整合微信多端页面授权之单点登录
- 生命苍白无力时候遇到你,即使再难也要亲手绘出五彩生活――读《平凡的世界》有感
- socket协议基础知识
- 在UIToolbar上创建左箭头按钮(如UINavigationBar的“后退”样式)
热门文章
- 农村将迎来重大爆发!传统农业链条正在重塑,关键一步已经迈出!
- 常用软件密码破解完全指南[转]
- 莫比乌斯(Mobius)反演知识整合
- 快速fcm matlab,FCM的MATLAB实现
- 非计算机专业考计算机三级难吗,经验之谈:怎样通过计算机等级考试三级考试...
- Java:输入年月日,输出这一天是这一年的第几天。
- jsp开发中cannot resolve taglib with uri的解决方法
- Matlab/Simulink中的S函数模块嵌入人工智能、神经网络算法设计仿真案例详解(以基于RBF神经网络算法的VSG转动惯量自调节为例)
- assaasasas
- 9类人事管理场景应用,泛微协助HR释放更多工作量