字符串问题总结

本文总结了字符串处理中的两个经典问题:最长公共子序列(LCS)和最长公共子串。通过动态规划方法,分别解释了两者的解题思路和状态转移方程。在LCS问题中,最长公共子序列不需连续,而最长公共子串要求连续。举例说明了如何找到A="HelloWorld"和B="loop"的LCS与子串,并给出了相应的代码实现。

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

1、最长公共子序列问题(LCS问题)
给定两个字符串A和B,长度分别为m和n,要求找出它们最长的公共子序列,并返回其长度。例如:
A = “HelloWorld”
B = “loop”
则A与B的最长公共子序列为"loo",返回长度为3。
动态规划解法:
定义子问题:
dp[i][j]为字符串A的第一个字符到第i个字符串和字符串B的的第一个字符到第j个字符的最长公共子序列,如A为“app”,B为“apple”,dp[2][3]表示“ap”和“app”的最长公共子串。注意到代码中dp的大小为(n+1)x(m+1),这多出来的一行和一列是第0行和第0列。
初始条件:
“”和任意字符串的都为0,所以dp[i][0]和dp[0][j]都为0。
状态方程:
在这里插入图片描述
代码如下:

int findLCS(string str1, string str2) {
	int m = str1.size(), n = str2.size();
	vector<vector<int> > dp(m + 1, vector<int>(n + 1));
	for (int i = 0; i <= m; i++) {
		dp[i][0] = 0;
	}
	for (int j = 0; j <= n; j++) {
		dp[0][j] = 0;
	}
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			if (str1[i] == str2[j]) {
				dp[i][j] = dp[i - 1][j - 1]+1;
			}
			else {
				dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
			}
		}
	}
	return dp[m][n];
}

2、最长公共子串问题
给定两个字符串A和B,长度分别为m和n,要求找出它们最长的公共子串,并返回其长度。例如:
A = “HelloWorld”
B = “loop”
子问题:
定义dp[i][j]表示以A中第i个字符结尾的子串和B中第j个字符结尾的子串的的最大公共子串(公共子串实际上指的是这两个子串的所有部分)的长度(要注意这里和LCS的不同,LCS中的dp[i+1][j+1]一定是大于等于dp[i][j]的;但最长公共子串问题就不一定了,它的dp[i][j]表示的子串不一定是以A[0]开头B[0]开头的,但是一定是以A[i-1]、B[j-1]结尾的),同样地, dp 的大小也为 (n + 1) x (m + 1) ,这多出来的一行和一列是第 0 行和第 0 列,初始化为 0,表示空字符串和另一字符串的子串的最长公共子串。
边界:
当我们要求dp[i][j],我们要先判断A的第i个元素B的第j个元素是否相同即判断A[i - 1]和 B[j -1]是否相同,如果相同它就是dp[i - 1][j- 1] + 1,相当于在两个字符串都去掉一个字符时的最长公共子串再加 1;否则最长公共子串取0。所以整个问题的初始状态为:
在这里插入图片描述
状态转移方程:
在这里插入图片描述

int findLong(string str1, string str2) {
	int m = str1.size(), n = str2.size();
	vector<vector<int> > dp(m + 1, vector<int>(n + 1));
	for (int i = 0; i <= m; i++) {
		dp[i][0] = 0;
	}
	for (int j = 0; j <= n; j++) {
		dp[0][j] = 0;
	}
	int maxLong = 0;
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			if (str1[i] == str2[j]) {
				dp[i][j] = dp[i - 1][j - 1] + 1;
			}
			else {
				dp[i][j] = 0;
			}
			maxLong = max(maxLong, dp[i][j]);
		}
	}
	return maxLong;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值