数据结构之字符串的最长公共子序列问题详解与示例(C,C++)

文章目录

  • 1、最长公共子序列定义
  • 2、动态规划解法
  • 3、状态转移方程
    • 初始化
    • 构建最长公共子序列
  • 4、C 和 C++ 实现示例
    • C 语言实现
    • C++ 语言实现
  • 5、总结

在这里插入图片描述


字符串的最长公共子序列(Longest Common Subsequence, LCS)是计算机科学中的一个经典问题,属于动态规划(Dynamic Programming, DP)的范畴。在本博客中,我们将详细讲解最长公共子序列的概念,并给出 C 和 C++ 语言的实现示例。

1、最长公共子序列定义

最长公共子序列问题可以这样描述:给定两个字符串序列 X 和 Y,求出它们的最长公共子序列 Z。这里的子序列指的是原序列中元素顺序的连续序列,但不要求元素在原序列中连续。例如,ABCD 和 ACDF 的一个最长公共子序列是 ACD。

2、动态规划解法

动态规划是解决此类问题的一种高效方法,其基本思想是将大问题分解为小问题,先求解小问题,然后利用这些小问题的解来构造原问题的解。对于最长公共子序列问题,我们可以用一个二维数组 dp 来存储两个字符串的前缀的公共子序列长度。

3、状态转移方程

假设我们有两个字符串 X[1…n] 和 Y[1…m],动态规划表 dp[][] 的第 i 行第 j 列的元素表示 X[1…i] 和 Y[1…j] 的公共子序列的长度。状态转移方程如下:

  • 当 X[i] = Y[j] 时,dp[i][j] = dp[i-1][j-1] + 1;
  • 当 X[i] != Y[j] 时,dp[i][j] = max(dp[i-1][j], dp[i][j-1])。

这里 dp[i-1][j-1] 表示 X[1…i-1] 和 Y[1…j-1] 的公共子序列长度,dp[i-1][j] 表示 X[1…i] 和 Y[1…j-1] 的公共子序列长度,dp[i][j-1] 表示 X[1…i-1] 和 Y[1…j] 的公共子序列长度。

初始化

初始化 dp[0][j] = 0 (对于所有 0 <= j < m)和 dp[i][0] = 0 (对于所有 0 <= i < n),因为任何序列与一个空序列都有一个公共子序列长度为0。

构建最长公共子序列

根据动态规划表,我们可以从 dp[n][m] 开始,逆向追踪得到最长公共子序列 Z[1…n+m]。当我们得到 dp[i][j] 时,有两种情况:

如果 X[i] = Y[j],则 Z[k] = X[i] 并且 k++,然后我们递归地求 dp[i-1][j-1];
如果 X[i] != Y[j],则我们分别递归地求 dp[i-1][j] 和 dp[i][j-1],取较大的一个。

4、C 和 C++ 实现示例

下面是使用 C 和 C++ 语言实现最长公共子序列的代码示例:

C 语言实现

#include <stdio.h>
#include <string.h>void printLCS(char X[], char Y[], int dp[][100]) {int m = strlen(X);int n = strlen(Y);int i, j;for (i = m, j = n; i > 0 && j > 0; i--, j--) {if (X[i - 1] == Y[j - 1]) {printf("%c", X[i - 1]);X++;Y++;} else if (dp[i - 1][j] > dp[i][j - 1]) {i--;} else {j--;}}
}int LCSLength(char X[], char Y[], int m, int n) {int dp[100][100];int i, j;// 初始化动态规划表for (i = 0; i <= m; i++) {dp[i][0] = 0;}for (j = 0; j <= n; j++) {dp[0][j] = 0;}// 动态规划填表for (i = 1; i <= m; i++) {for (j = 1; j <= n; j++) {if (X[i - 1] == Y[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = (dp[i - 1][j] > dp[i][j - 1]) ? dp[i - 1][j] : dp[i][j - 1];}}}// 打印最长公共子序列printLCS(X, Y, dp);return dp[m][n];
}int main() {char X[] = "AGGTAB";char Y[] = "GXTXAYB";int m = strlen(X);int n = strlen(Y);printf("最长公共子序列的长度为 %d\n", LCSLength(X, Y, m, n));return 0;
}

C++ 语言实现

#include <iostream>
#include <vector>
#include <string>std::string LCS(const std::string& X, const std::string& Y) {int m = X.length();int n = Y.length();std::vector<std::vector<int>> dp(m + 1, std::vector<int>(n + 1, 0));std::string lcs;// 动态规划填表for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (X[i - 1] == Y[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = (dp[i - 1][j] > dp[i][j - 1]) ? dp[i - 1][j] : dp[i][j - 1];}}}// 构建最长公共子序列int i = m, j = n;while (i > 0 && j > 0) {if (X[i - 1] == Y[j - 1]) {lcs += X[i - 1];i--;j--;} else if (dp[i - 1][j] > dp[i][j - 1]) {i--;} else {j--;}}// 输出结果std::reverse(lcs.begin(), lcs.end());std::cout << "最长公共子序列是: " << lcs << std::endl;return lcs;
}int main() {std::string X = "AGGTAB";std::string Y = "GXTXAYB";std::string lcs = LCS(X, Y);return 0;
}

在这两个示例中,我们首先初始化了一个动态规划表 dp,然后使用状态转移方程填充它。最后,我们通过回溯动态规划表来构建并打印最长公共子序列。在 C++ 示例中,我们使用了 std::vector 来存储动态规划表,这使得代码更加清晰和易于管理。

5、总结

本文详细介绍了最长公共子序列(LCS)问题的原理,并通过C/C++语言给出了具体的实现。LCS问题是一个经典的动态规划问题,通过构建状态转移方程,我们可以高效地求解两个字符串的最长公共子序列。在实际应用中,LCS问题可以扩展到多个字符串的情况,也可以结合其他算法优化求解过程,如后缀数组、后缀树等。

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

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

相关文章

接口开发:Orcal数据库的批量新增sql

场景&#xff1a;在日常的CURD中一定会用到批量新增。在我们的项目中&#xff0c;使用的数据库是Orcal&#xff0c;由于之前基本都是使用Mysql的&#xff0c;使用的sql语句也基本都是用mysql的。但是在这次的接口编写时用mysql的批量新增出了问题&#xff0c;刚开始我还以为是写…

[MySQL]02 存储引擎与索引,锁机制,SQL优化

Mysql存储引擎 可插拔式存储引擎 索引是在存储引擎底层上实现的 inno DB MySQL默认存储引擎: inno DB高可靠性和高性能的存储引擎 DML操作遵循ACID模型支持事务行级锁,提高并发访问性能支持外键 约束,保证数据完整性和可靠性 MySAM MySAM是MySQL的早期引擎 特点: 不支持事…

OmniFocus4 归档和备份

归档和备份 当您的数据库变得臃肿、缓慢或者充斥着过时内容时&#xff0c;或者您需要回到之前的数据版本时&#xff0c;OmniFocus for Mac 的归档和备份功能可以帮您实现心愿。 创建归档 每天使用 OmniFocus 后不久&#xff0c;数据库可能会变得很大&#xff0c;在与移动设备…

安装 VMware vSphere vCenter 8.0

安装 VMware vSphere vCenter 8.0 1、运行安装程序 2、语言选择中文 3、点下一步 4、接受许可协议&#xff0c;点下一步 5、填写部署vCenter服务的ESXI主机IP地址以及对应ESXI主机的账号密码&#xff0c;这里将vCenter服务部署在192.168.1.14这台ESXi主机上 6、接受证书警告 7…

自动化测试中如何应对网页弹窗的挑战!

在自动化测试中&#xff0c;网页弹窗的出现常常成为测试流程中的一个难点。无论是警告框、确认框、提示框&#xff0c;还是更复杂的模态对话框&#xff0c;都可能中断测试脚本的正常执行&#xff0c;导致测试结果的不确定性。本文将探讨几种有效的方法来应对网页弹窗的挑战&…

21k star 开源项目,让模糊图像秒变高清!

不知道大家有没有遇到这样的需求&#xff1a;电脑里有一些很久之前保存的好看的图片&#xff0c;但是因为分辨率不高&#xff0c;当做壁纸使用会变得模糊。或者是从网上下载的需要使用的图片&#xff0c;找不到更高清的版本导致使用效果不好。之前分享过基于 Real-ESRGAN 算法修…

Redis中的哨兵(Sentinel)

上篇文章我们讲述了Redis中的主从复制&#xff08;Redis分布式系统中的主从复制-CSDN博客&#xff09;&#xff0c;本篇文章针对主从复制中的问题引出Redis中的哨兵&#xff0c;希望本篇文章会对你有所帮助。 文章目录 一、引入哨兵机制 二、基本概念 三、主从复制的问题 四、哨…

autosar mcal I2C

autosar mcal I2C 1. I2C 基本参数1.1 I2C通信总线基本概念1.2 I2C通信速率1.3 I2C 通信地址2. I2C数据格式2.1 I2C 写2.2 读操作3. I2C EB trosos配置4. I2C使用思考1. I2C 基本参数 [!warning] AUTOSAR 无IIC I2C不是一个标准的AUTOSAR 驱动模块,但是大部分芯片厂商会把它封…

php相关

php相关 ​ 借鉴了小迪安全以及各位大佬的博客&#xff0c;如果一切顺利&#xff0c;会不定期更新。 如果感觉不妥&#xff0c;可以私信删除。 默认有php基础。 文章目录 php相关1. php 缺陷函数1. 与2. MD53. intval()4. preg_match() 2. php特性1. php字符串解析特性2. 杂…

【MySQL进阶篇】存储对象:视图、存储过程及触发器

一、视图 1、介绍 视图&#xff08;view&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来定义视图的查询中使用的表&#xff08;基表&#xff09;&#xff0c;并且是在使用视图时动态生成的。 通俗的讲&#xff0c;视图只保存了…

Android笔试面试题AI答之Activity(2)

答案仅供参考&#xff0c;大部分为文心一言AI作答 目录 1. 请介绍一下Activity 生命周期&#xff1f;1. 完全生命周期2. 可见生命周期3. 前台生命周期4. 配置更改5. 特殊场景 2. 请介绍一下横竖屏切换时Activity的生命周期变化&#xff1f;1.默认行为&#xff08;未设置androi…

Cisco 路由重发布 —— 实现路由信息在不同路由域间的传递

一、技术背景 在实际的组网中&#xff0c;可能会遇到这样一个场景&#xff1a;在一个网络中同时存在两种或者两种以上的路由协议。例如客户的网络原先是纯 Cisco 的设备&#xff0c;使用 EIGRP 协议将网络的路由打通。但是后来网络扩容&#xff0c;增加了一批华为的设备&#…

【题解 Kruskal重构树 LCA】 星际导航

星际导航 分析&#xff1a; 这也是一个比较老的题目了 今天突然想学一下kruskal重构树&#xff0c;就做到了这个题。 首先我们要明白&#xff0c;为什么这道题的路径一定是在最小生成树里&#xff1f; 或许是我们惯有的经验&#xff1a;最小的最大或者最大的最小无非两种套路…

信号【Linux】

文章目录 信号处理方式&#xff08;信号递达&#xff09;前后台进程 终端按键产生信号kill系统调用接口向进程发信号阻塞信号sigset_tsigprocmasksigpending内核态与用户态&#xff1a;内核空间与用户空间内核如何实现信号的捕捉 1、信号就算没有产生&#xff0c;进程也必须识别…

题解:T480718 eating

eating 题目背景 从前有个荣光的王国&#xff0c;小 A 是里面的国王&#xff0c;今天他要赐予他的子民以仓廪。 题目描述 在一条街上有 n n n 个饭店。小 A 站在这条街的最左端。 第 i i i 个饭店离这条街最左端的距离是 a i a_i ai​&#xff0c;它所售卖的菜品的美味…

【C++】C++类和对象详解(上)

目录 思维导图大纲&#xff1a; 思维方面&#xff1a; 1. 类的定义&#xff1a; 2. 类的特点&#xff1a; 3. this指针&#xff1a; 4. 类的默认成员函数 默认构造函数 1.构造函数 2.析构函数 3.拷贝构造函数 4. 赋值运算符重载 1. 运算符重载 5. 日期类实现&#…

【CPP】CPP的内存管理

目录 10 C/C内存管理10.1 内存分布10.2 C的动态内存管理10.3 C的内存管理10.4 new失败的检测10.5 operator new与operator delete函数10.5 new与malloc()的区别,delete与free()的区别10.6 定位new表达式 这里是oldking呐呐,感谢阅读口牙!先赞后看,养成习惯! 个人主页:oldking呐…

编程中的智慧四:设计模式总览

前面三篇我们通过从一些零散的例子&#xff0c;和简单应用来模糊的感受了下设计模式在编程中的智慧&#xff0c;从现在开始正式进入设计模式介绍&#xff0c;本篇将从设计模式的7大原则、设计模式的三大类型、与23种设计模式的进行总结&#xff0c;和描述具体意义。 设计模式体…

怎样在 Nginx 中配置防盗链?

文章目录 怎样在 Nginx 中配置防盗链&#xff1f;一、什么是盗链&#xff1f;二、Nginx 防盗链的原理三、Nginx 防盗链的配置步骤四、防盗链配置的实际应用示例五、常见问题及解决方法六、总结 怎样在 Nginx 中配置防盗链&#xff1f; 在当今数字化的时代&#xff0c;网站内容…

使用Diffusion Models进行街景视频生成

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;街景图生成相当有挑战性&#xff0c;目前的文本到视频的方法仅限于生成有限范围的场景的短视频&#xff0c;文本到3D的方法可以生成单独的对象但不是整个城市。除此之外街景图对一致性的要求相当高&#x…