最长公共子串/子序列

最长公共子串:找两个字符串的最长公共子串,要求在原字符串中是连续的

最长公共子序列:不要求连续

最长公共子串思路:

声明一个二维数组dp[][]来存放相对应的最长公共子串数

            arr1[m]=arr2[n]时,dp[m+1][n+1]=1+dp[m][n]  即当子序列中第 m+1 元素与目标序列中第 n+1 元素相同时,子序列前 m+1 个元素与目标序列前 n+1 个元素的最长公共子串数为子序列前 m 个元素与目标序列前 n 个元素的最长公共子串数 + 1;

            arr1[m] != arr2[n]时,dp[m+1][n+1]=0;即当子序列中第 m+1 元素与目标序列中第 n+1 元素不相同时,子序列前 m+1 个元素与目标序列前 n+1 个元素的最长公共子串长为0 ;第二步:找出最大值,依次输出其左上角


#include<stdio.h>
int weight[101];//子串权值
char substr[101];//子串字母
char sbustrs[100][100];//
int maxlcs=0;//LCS大小
int a=0;
char arr1[]="bab";
char arr2[]="caba";
int dp[101][101]={0};//dp[i][j]存放字串前i-1,目标串前j-1个元素的LCS,初始全为0
int LCS(char *arr1,int size1 ,char *arr2,int size2 )//求出dp[][];
{
	for(int i=0 ;i < size1; i++ )//依次增加子序列长度
	{
		for(int j=0 ;j< size2; j++)//依次增加目标序列长度
		{
			if(arr1[i]==arr2[j])
			{
				dp[j+1][i+1]=dp[j][i]+1;//当前匹配相同,对应LCS等于前一LCS+1
				if(maxlcs<dp[j+1][i+1])maxlcs= dp[j+1][i+1];//找到LCS的最大值
			}
			else dp[j+1][i+1]=0;//当前匹配不同,对应LCS等于左侧和上侧LCS中的较大值
		}
	}
	return 0;
}
int Find ( int n ,int m ,int nextmax )//找出所有匹配点,记录相应字符和权值
{ 
	int k, j;
	if (nextmax==0){ printf("\n");return 0;}
	for(k=m+n ; k>0 ;k--)
	{
		for( j=n ; j>0 && (k-j)<(m+1) ; j--)
		{
			if(dp[k-j][j]==nextmax)
			{
			        printf("%d %d %d",k-j,j,nextmax);
				printf("%c   ",arr1[j-1]);
				if (nextmax==0) printf("\n");
				Find(j-1,k-j-1,nextmax-1);//递归查找下一层级
			}
		}
	}
	return 0;
}
int main()
{
	LCS(arr1,3,arr2,4);
	Find(3,4,maxlcs);
	return 0;
}


   

最长公共子序列思路:

第一步:声明一个二维数组dp[][]来存放相对应的最长公共子序列数

              arr1[m]=arr2[n]时,dp[m+1][n+1]=1+dp[m][n]  即当子序列中第 m+1 元素与目标序列中第 n+1 元素相同时,子序列前 m+1 个元素与目标序列前 n+1 个元素的最长公共子序列数为子序列前 m 个元素与目标序列前 n 个元素的最长公共子序列数 + 1;

              arr1[m] != arr2[n]时,dp[m+1][n+1]=max{dp[m][n+1],dp[m+1][n]} 即当子序列中第 m+1 元素与目标序列中第 n+1 元素不相同时,子序列前 m+1 个元素与目标序列前 n+1 个元素的最长公共子序列数为子序列前 m 个元素与目标序列前 n+1 个元素的最长公共子序列数 和 子序列前 m+1 个元素与目标序列前 n 个元素的最长公共子序列数中的较大值 ;

第二步:递归找出每一个匹配点对应的子序列,递归输出

  1 #include<stdio.h>
  2 char substr[101];//子串字母
  3 int maxlcs=0;//LCS大小
  4 char arr1[]="DADFDAB";
  5 char arr2[]="ABDEFAFCD";
  6 int dp[101][101]={0};//dp[i][j]存放字串前i-1,目标串前j-1个元素的LCS,初始全为0
  7 int LCS(char *arr1,int size1 ,char *arr2,int size2 )//求出dp[][];
  8 {
  9         for(int i=0 ;i < size1; i++ )//依次增加子序列长度
 10         {
 11                 for(int j=0 ;j< size2; j++)//依次增加目标序列长度
 12                 {
 13                         if(arr1[i]==arr2[j]) dp[j+1][i+1]=dp[j][i]+1;//当前匹配相同,对应LCS等于前一LCS+1
 14                         else dp[j+1][i+1]=(dp[j+1][i]>dp[j][i+1]?dp[j+1][i]:dp[j][i+1]);//当前匹配不同,对应LCS等于左侧和上侧LCS中的较大值
 15                 }
 16         }
 17         maxlcs= dp[size2][size1];//找到LCS的最大值
 18         return 0;
 19 }
 20 int Find ( int n ,int m ,int nextmax )//找出所有匹配点,记录相应字符和权值
 21 {
 22         int k, j;
 23         if (nextmax==0){ printf("%s \n",substr);return 0;}//当找到首个元素后输出记录
 24         for(k=m+n ; k>0 ;k--)
 25         {
 26                 for( j=n ; j>0 && (k-j)<(m+1) ; j--)
 27                 {
 28                         if((dp[k-j][j]==nextmax) && (arr1[j-1]==arr2[k-j-1]))//权值为当前最大,且对应字母匹配则记录
 29                         {
 30                                 substr[maxlcs-nextmax]=arr1[j-1];//将记录存入数组与递归层数相对应位置,新分支覆盖原有分支,保留共用部分
 31                                 Find(j-1,k-j-1,nextmax-1);//递归查找下一层级
 32                         }
 33                 }
 34         }
 35         return 0;
 36 }
 37 int main()
 38 {
 39         LCS(arr1,7,arr2,9);
 40         Find(7,9,maxlcs);
 41         return 0;
 42 }






### C++ 实现最长公共子串最长公共子序列的暴力算法 #### 最长公共子串的暴力求解方法 以下是基于暴力枚举的方法来寻找两个字符串之间的最长公共子串: ```cpp #include <iostream> #include <vector> #include <string> using namespace std; void findLongestCommonSubstring(const string& s1, const string& s2) { int maxLength = 0; string result = ""; for (int i = 0; i < s1.length(); ++i) { for (int j = 0; j < s2.length(); ++j) { int k = 0; while ((i + k) < s1.length() && (j + k) < s2.length() && s1[i + k] == s2[j + k]) { k++; } if (k > maxLength) { maxLength = k; result = s1.substr(i, k); } } } cout << "最长公共子串为:" << result << endl; } int main() { string str1 = "cnblogs"; string str2 = "belong"; findLongestCommonSubstring(str1, str2); return 0; } ``` 此代码通过双重循环遍历 `s1` 和 `s2` 的每一个位置,尝试匹配从当前位置开始的最大相同部分[^2]。 --- #### 最长公共子序列的暴力求解方法 对于最长公共子序列问题,可以使用递归来穷尽所有可能性并找到最优解。以下是一个简单的暴力实现方式: ```cpp #include <iostream> #include <string> using namespace std; // 辅助函数用于计算LCS长度 int lcsLength(string X, string Y, int m, int n) { if (m == 0 || n == 0) return 0; if (X[m - 1] == Y[n - 1]) return 1 + lcsLength(X, Y, m - 1, n - 1); else return max(lcsLength(X, Y, m, n - 1), lcsLength(X, Y, m - 1, n)); } // 主程序入口 int main() { string str1 = "cnblogs"; string str2 = "belong"; int length = lcsLength(str1, str2, str1.length(), str2.length()); cout << "最长公共子序列的长度为:" << length << endl; return 0; } ``` 该代码的核心在于递归地判断当前字符是否相等,并分别处理三种情况:继续向前探索、跳过第一个字符串中的字符或者跳过第二个字符串中的字符[^1]。 --- ### 结果分析 - **最长公共子串**的结果依赖于连续性条件,在上述例子中会输出 `"lo"`。 - **最长公共子序列**则不需要考虑连续性,因此其结果可能是 `"blog"` 或其他符合条件的组合[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值