【动态规划】【字符串】1092. 最短公共超序列

news2024/11/19 4:21:02

作者推荐

【动态规划】【前缀和】【C++算法】LCP 57. 打地鼠

本文涉及知识点

动态规划汇总

LeetCode1092最短公共超序列

给你两个字符串 str1 和 str2,返回同时以 str1 和 str2 作为 子序列 的最短字符串。如果答案不止一个,则可以返回满足条件的 任意一个 答案。
如果从字符串 t 中删除一些字符(也可能不删除),可以得到字符串 s ,那么 s 就是 t 的一个子序列。
示例 1:
输入:str1 = “abac”, str2 = “cab”
输出:“cabac”
解释:
str1 = “abac” 是 “cabac” 的一个子串,因为我们可以删去 “cabac” 的第一个 "c"得到 “abac”。
str2 = “cab” 是 “cabac” 的一个子串,因为我们可以删去 “cabac” 末尾的 “ac” 得到 “cab”。
最终我们给出的答案是满足上述属性的最短字符串。
示例 2:
输入:str1 = “aaaaaaaa”, str2 = “aaaaaaaa”
输出:“aaaaaaaa”
提示:
1 <= str1.length, str2.length <= 1000
str1 和 str2 都由小写英文字母组成。

动态规划

原理

超串一定以str1.back或str2.back结尾 。

动态规划的状态表示

dp[i][j][use]=x,表示str1[0,i)和str2[0,j)的最短超串长度。use的含义如下:
{ 此超串的末尾已经匹配了 s t r 1 , s t r 2 3 此超串末尾匹配了 s t r 1 1 此超串末尾匹配了 s t r 2 2 \begin{cases} 此超串的末尾已经匹配了str1,str2 & 3 \\ 此超串末尾匹配了str1 & 1 \\ 此超串末尾匹配了str2 & 2 \end{cases} 此超串的末尾已经匹配了str1,str2此超串末尾匹配了str1此超串末尾匹配了str2312

动态规划的转移方程

dp[i][j][use] 更新dp[i+1][j][use1] preCh = (1&use) ? str1[i-1] : str2[j-1]。const int use1 = bNew ? 1 : (1 | use);
{ d p [ i + 1 ] [ j ] [ u s e 1 ] = m i n ( , d p [ i ] [ j ] [ u s e ] + 1 ) ( p r e C h ! = s t r 1 [ i ] ) 或 ( 1 位与 u s e ) d p [ i + 1 ] [ j ] [ u s e 1 ] = m i n ( , d p [ i ] [ j ] [ u s e ] ) e l s e \begin{cases} dp[i+1][j][use1] = min(,dp[i][j][use]+1) & (preCh!=str1[i])或(1位与use) \\ dp[i+1][j][use1] = min(,dp[i][j][use]) & else \\ \end{cases} {dp[i+1][j][use1]=min(,dp[i][j][use]+1)dp[i+1][j][use1]=min(,dp[i][j][use])(preCh!=str1[i])(1位与use)else
更新dp[i][j+1] [use1]类似

动态规划的填表顺序

I+j之和从1到大处理,use 从1到3,这样可以保证动态规划的无后效性。

动态规划的初始值

dp[1][0][1] =1;
dp[0][1][2] = 1;
其它dp 的值INT_MAX/2

动态规划的返回值

根据dp2 逆序组装。

代码

核心代码

class Solution {
public:
	string shortestCommonSupersequence(string str1, string str2) {
		m_r = str1.length();
		m_c = str2.length();
		vector<vector<vector<int>>> dp(m_r + 1, vector<vector<int>>(m_c + 1,vector<int>(4, INT_MAX / 2)));
		dp[1][0][1] =1;		
		dp[0][1][2] = 1;
		for (int len = 1; len < m_r + m_c; len++)
		{
			for (int len1 = max(0,len-m_c); len1 <= min(len, m_r); len1++)
			{
				const int len2 = len - len1;
				for (int use = 1; use <= 3; use++)
				{
					const int preLen = dp[len1][len2][use];
					if (preLen >= INT_MAX / 2)
					{
						continue;
					}
					const char preCh = (1 & use) ? str1[len1 - 1] : str2[len2 - 1];
					if (len1 < m_r)
					{
						bool bNew = (preCh != str1[len1]) || (1 & use );
						const int use1 = bNew ? 1 : (1 | use);
						const int iNewLen = preLen + bNew;
						dp[len1 + 1][len2][use1] = min(dp[len1 + 1][len2][use1], iNewLen);		
					}
					if (len2 < m_c)
					{
						bool bNew = (preCh != str2[len2]) || (2 & use );
						const int use1 = bNew ? 2 : (2 | use);
						const int iNewLen = preLen + bNew;
						dp[len1 ][len2 + 1][use1] = min(dp[len1][len2 + 1][use1], iNewLen);
					}
				}				
			}
		}
		
		string strRet;
		for (int len1 = m_r, len2 = m_c; len1 + len2 > 0; )
		{
			int use = std::min_element(dp[len1][len2].begin(), dp[len1][len2].end()) - dp[len1][len2].begin();
			const char preCh = (1 & use) ? str1[len1 - 1] : str2[len2 - 1];
			strRet += preCh;
			if (1 & use )
			{
				len1--;
			}
			if (2 & use )
			{
				len2--;
			}
		}
		std::reverse(strRet.begin(), strRet.end());
		return strRet;
	}
	int m_r, m_c;
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{	
	string str1,str2;
	{
		Solution sln;
		str1 = "abac", str2 = "cab";
		auto res = sln.shortestCommonSupersequence(str1, str2);
		assert(-1 != res.find(str1));
		assert(-2 != res.find(str1));
		Assert((int)res.length(),5 );
	}
	{
		Solution sln;
		str1 = "aaaaaaaa", str2 = "aaaaaaaa";
		auto res = sln.shortestCommonSupersequence(str1, str2);
		assert(-1 != res.find(str1));
		assert(-2 != res.find(str1));
		Assert(res.length(), string("aaaaaaaa").length());
	}
}

2023年1月版

先求最长公共子序列。
如果str1[i]==str2[j], 则一个字符匹配两个串。
否则比较dp[i-1][j] 和dp[i][j-1],采用公共子序列大的。

class Solution {
public:
string shortestCommonSupersequence(string str1, string str2) {
vector<vector> dp;
{
dp.assign(str1.length() + 1, vector(str2.length() + 1));
for (int i = 1; i <= str1.length(); i++)
{
for (int j = 1; j <= str2.length(); j++)
{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if (str1[i-1] == str2[j-1])
{
dp[i][j] = max(dp[i][j],dp[i - 1][j - 1] + 1);
}
}
}
}
string str;
int i = str1.length();
int j = str2.length();
str1 = " " + str1;
str2 = " " + str2;
while (i > 0 || j > 0)
{
if (0 == i)
{
str += str2[j–];
}
else if (0 == j)
{
str += str1[i–];
}
else if (str1[i] == str2[j])
{
str += str1[i];
i–, j–;
}
else
{
if (dp[i - 1][j] == dp[i][j])
{
str += str1[i–];
}
else
{
str += str2[j–];
}
}
}
return std::string(str.rbegin(), str.rend());
}
};

2023年8月版

class Solution {
public:
string shortestCommonSupersequence(string str1, string str2) {
m_c1 = str1.length();
m_c2 = str2.length();
vector<vector> dp(m_c1, vector(m_c2));
vector < vector<pair<int, int>>> vPre(m_c1, vector<pair<int, int>>(m_c2,std::make_pair<>(-1,-1)));
dp[0][0] = str1[0] == str2[0];
if (0 == dp[0][0])
{
vPre[0][0] = std::make_pair(0, -1);
}
for (int j = 1; j < m_c2; j++)
{
if (str1[0] == str2[j])
{
dp[0][j] = 1;
vPre[0][j] = std::make_pair(-1, j - 1);
}
else
{
dp[0][j] = dp[0][j - 1];
vPre[0][j] = std::make_pair(0, j - 1);
}
}
for (int i = 1; i < m_c1; i++)
{
if (str1[i] == str2[0])
{
dp[i][0] = 1;
vPre[i][0] = std::make_pair(i - 1, -1);
}
else
{
dp[i][0] = dp[i-1][0];
vPre[i][0] = std::make_pair(i-1,0);
}
}
for (int i = 1; i < m_c1; i++)
{
for (int j = 1; j < m_c2; j++)
{
if (str1[i] == str2[j])
{
dp[i][j] = 1 + dp[i - 1][j - 1];
vPre[i][j] = std::make_pair(i - 1, j - 1);
continue;
}
if (dp[i - 1][j] > dp[i][j - 1])
{
dp[i][j] = dp[i - 1][j];
vPre[i][j] = std::make_pair(i - 1, j);
}
else
{
dp[i][j] = dp[i ][j - 1];
vPre[i][j] = std::make_pair(i , j - 1);
}
}
}
int iNum = dp.back().back();
vector vRet;
auto it = std::make_pair(m_c1-1,m_c2-1);
for ( 😭-1 != it.first) && (-1 != it.second)😉
{
auto pre = vPre[it.first][it.second];
if (it.first != pre.first)
{
vRet.emplace_back(str1[it.first]);
}
else
{
vRet.emplace_back(str2[it.second]);
}
it = pre;
}
for (int i = it.first; i >= 0; i–)
{
vRet.emplace_back(str1[i]);
}
for (int i = it.second; i >= 0; i–)
{
vRet.emplace_back(str2[i]);
}
std::reverse(vRet.begin(), vRet.end());
vRet.emplace_back(0);
return vRet.data();
}
int m_c1, m_c2;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1442972.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++数据类型、变量常量

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 大家新年快乐&#xff0c;今天我们来学习C的数据类型&#xff0c;变量常量。 文章目录 1.数据类型的概念与思想 1.1基本数据类型 1.2复合数据类型 1.3类型修饰符 1.4类型转换 1.4.1static_cast 1.4.2…

【机器学习】数据清洗之处理缺失点

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步…

腾讯云4核8G服务器最大能承载多少用户在线?12M带宽

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…

HTML5和CSS3强化知识总结

HTML5的新特性 HTML5的新增特性主要是针对于以前的不足&#xff0c;增一些新的标签、新的表单和新的表单属性等。这些新特性都有兼容性问题&#xff0c;基本是IE9以上版本的浏览器才支持&#xff0c;如果不考虑兼容性问题&#xff0c;可以大量使用这些新特性。 HTML5新增的语义…

创建自己的系统创富法则,做个轻松赚钱的甩手掌柜

一、教程描述 本套系统创富教程&#xff0c;大小744.80M&#xff0c;共有28个文件。 二、教程目录 01.走遍全球四十多个国家&#xff0c;我才发现赚钱的本质如此雷同.mp4 02.靠工资技术赚钱太慢&#xff0c;想赚到自己的第一个一百万的方法是&#xff1f;.mp4 03.不服暴发…

uv机器电机方向极性

爱普生主板设置X、Y 电机方向极性&#xff1a;请根据实际情况设置&#xff0c;开机初始化时如果电机运动方向反了则修改此极性。 理光主板设置X、Y 电机方向极性

研究多态恶意软件,探讨网络安全与AI

前言 近期ChatGPT火遍全球&#xff0c;AI技术被应用到了全球各行各业当中&#xff0c;国内外各大厂商也开始推出自己的ChatGPT&#xff0c;笔者所在公司在前段时间也推出了自研的安全GPT&#xff0c;AI技术在网络安全行业得到了很多的应用&#xff0c;不管是网络安全研究人员、…

【51单片机】自定义静态数码管显示(设计思路&代码演示)

前言 大家好吖&#xff0c;欢迎来到 YY 滴单片机系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 本章节内容为【实现动静态数码管】项目的第三个模块完整章节&#xff1a;传送门 欢迎订阅 YY滴C专栏&#xff01;更多干货持…

【资料分享】基于单片机大气压监测报警系统电路方案设计、基于飞思卡尔的无人坚守点滴监控自动控制系统设计(程序,原理图,pcb,文档)

基于单片机大气压监测报警系统电路方案设计 功能&#xff1a;实现的是大气压检测报警系统&#xff0c;可以通过传感器实时检测当前大气压值&#xff0c;可以设定大气压正常范围&#xff0c;当超过设定范围进行报警提示。 资料&#xff1a;protues仿真&#xff0c;程序&#x…

SpringCloud-高级篇(十九)

我们已经学过使用 SpringAMQP去收和发消息&#xff0c;但是发和收消息是只是MQ最基本的功能了&#xff0c;在收发消息的过程中&#xff0c;会有很多的问题需要去解决&#xff0c;下面需要学习rabbitMQ的高级特性去解决 死信交换机&#xff1a;这个可以帮助我们实现消息的延迟的…

[office] excel求乘积的公式和方法 #媒体#笔记#经验分享

excel求乘积的公式和方法 本文首先给出两个常规的excel求乘积的链接&#xff0c;然后再例举了一个文字和数字在同一单元格里面的excel求乘积的公式写法。 excel求乘积的方法分为两种&#xff0c;第一种是直接用四则运算的*来求乘积&#xff0c;另外一种就是使用PRODUCT乘积函数…

【GO语言卵细胞级别教程】03.条件与循环语句

注意&#xff1a;以下演示所用的项目&#xff0c;在第一章节已经介绍了&#xff0c;这里不做赘述 目录&#xff1a; 【GO语言卵细胞级别教程】03.条件与循环语句1.条件语句1.1 if语句1.1.1 单层if语句1.1.2 if-else语句1.1.3 if-else-if 语句1.1.4 if 嵌套 1.2 switch 语句1.1…

[论文精读]Community-Aware Transformer for Autism Prediction in fMRI Connectome

论文网址&#xff1a;[2307.10181] Community-Aware Transformer for Autism Prediction in fMRI Connectome (arxiv.org) 论文代码&#xff1a;GitHub - ubc-tea/Com-BrainTF: The official Pytorch implementation of paper "Community-Aware Transformer for Autism P…

Python解决SSL不可用问题

参考&#xff1a;https://blog.csdn.net/weixin_44894162/article/details/126342591 一、问题描述&#xff1a; 报错概述&#xff1a; WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available. ## 警告:pip配…

空气质量预测 | Matlab实现基于BP神经网络回归的空气质量预测模型

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 政府机构使用空气质量指数 (AQI) 向公众传达当前空气污染程度或预测空气污染程度。 随着 AQI 的上升,公共卫生风险也会增加。 不同国家有自己的空气质量指数,对应不同国家的空气质量标准。 基于BP(Backpropag…

微服务学习 | Spring Cloud 中使用 Sentinel 实现服务限流

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie。 目录 前言 通过代码实现限流 定义资源 通过代码定义资源 通过注解方式定义资源 定义限流规则 通过…

反序列化漏洞——PHP原生类

Error类 PHP>7.0&#xff0c;因为存在__toString&#xff0c;可以进行XSS Exception类 因为存在__toString&#xff0c;可以进行XSS DirectoryIterator类 因为存在__toString&#xff0c;可以获取符合要求的第一个文件名 SplFileObject类 因为存在__toString&#xff0c…

深入浅出:Golang的Crypto/SHA256库实战指南

深入浅出&#xff1a;Golang的Crypto/SHA256库实战指南 介绍crypto/sha256库概览主要功能应用场景库结构和接口实例 基础使用教程字符串哈希化文件哈希化处理大型数据 进阶使用方法增量哈希计算使用Salt增强安全性多线程哈希计算 实际案例分析案例一&#xff1a;安全用户认证系…

缺省参数(c++)

void fun(int a0) { cout<<a<<endl; } 当我们调用函数时: fun(10) 输出10; fun&#xff08;&#xff09; 未传参时&#xff1a; 输出0; 未传参时a就会接受0&#xff0c;相当于这个0就是“备胎” 传参了0就没有用 全缺省 void fun2(int a10,int b3,int…

力扣刷题之旅:进阶篇(六)—— 图论与最短路径问题

力扣&#xff08;LeetCode&#xff09;是一个在线编程平台&#xff0c;主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目&#xff0c;以及它们的解题代码。 --点击进入刷题地址 引言 在算法的广阔天地中&#xff0c;图论是一个非常重要的领域。…