公共字串计算(最长公共子串/序列)C++
描述
题目标题:
计算两个字符串的最大公共字串的长度,字符不区分大小写
输入
输入两个字符串
输出
输出一个整数
样例输入
asdfas werasdfaswer
样例输出
6
思路
暴力求解
此题用cin即可
代码
#include <iostream>
#include <string>
using namespace std;
int Maxsubstr(string a,string b)
{unsigned int start1,start2;int count=0,Max=0;for(unsigned int i=0; a[i]!='\0'; i++){for(unsigned int j=0; b[j]!='\0'; j++){start1=i;start2=j;while(a[start1]==b[start2] && start1<a.length() && start2<b.length()){start1++;start2++;count++;}if(count>Max){Max=count;}count=0;}}return Max;
}int main()
{string str1,str2;cin>>str1;cin>>str2;//不区分大小写for (unsigned int i=0; i<str1.length(); i++){str1[i]=tolower(str1[i]);}for (unsigned int i=0; i<str2.length(); i++){str2[i]=tolower(str2[i]);}cout<<Maxsubstr(str1,str2)<<endl;
}
题目
描述
查找两个字符串a,b中的最长公共子串。
详细描述:
查找两个字符串a,b中的最长公共子串。
输入
输入两个字符串
输出
返回重复出现的字符
样例输入
abcdefghijklmnop
abcsafjklmnopqrstuvw
样例输出
jklmnop
思路
暴力求解
代码
#include <iostream>
#include <string>
using namespace std;
int Maxsubstr(string a,string b,string *&s)
{unsigned int start,start1,start2;int count=0,Max=0;for(unsigned int i=0; a[i]!='\0'; i++){for(unsigned int j=0; b[j]!='\0'; j++){start1=i;start2=j;while(a[start1]==b[start2] && start1<a.length() && start2<b.length()){start1++;start2++;count++;}if(count>Max){start = i;Max = count;}count=0;}}//保存字符串s=new string[Max+1];for(int i=0; i<Max; i++){s[i]=a[i+start];}s[Max]='\0';return Max;
}int main()
{string str1,str2,*str; cin>>str1>>str2;//此题输入-------------//getline(cin,str1);//getline(cin,str2);int length = Maxsubstr(str1,str2,str);for(int i=0; i<length; i++){cout<<str[i];}cout<<endl;return 0;
}
如果你看到这里觉得暴力方法太low
Low。。。。
哎,那就聊聊动态规划版的经典问题《最长公共子串(序列)》
子串是连续的,子序列可以是不连续的。
状态转移方程:
符号约定,C1是S1的最右侧字符,C2是S2的最右侧字符,S1‘是从S1中去除C1的部分,S2’是从S2中去除C2的部分。
LCS(S1,S2)等于下列3项的最大者:
(1)LCS(S1,S2′′)
(2)LCS(S1′′,S2)
(3)LCS(S1′′)+C1 —如果C1等于C2;
边界终止条件:如果S1和S2都是空串,则结果也是空串。
下面我们同样要构建一个矩阵来存储动态规划过程中子问题的解。这个矩阵中的每个数字代表了该行和该列之前的LCS的长度。与上面刚刚分析出的状态转移议程相对应,矩阵中每个格子里的数字应该这么填,它等于以下3项的最大值:
(1)上面一个格子里的数字
(2)左边一个格子里的数字
(3)左上角那个格子里的数字(如果 C1不等于C2); 左上角那个格子里的数字+1( 如果C1等于C2)
#include<iostream>
#include<cstring>
#include <vector>using namespace std;void SubSequence(vector<vector<string>> &flag,string str1, string str2,int i,int j);
void display(int *result,string str1,string str2);void initialVector(vector<vector<string>> &vectorAll,int len)
{for(int i=0; i<len; ++i){vector<string> temp;vectorAll.push_back(temp);}
}int lcs_string(string str1, string str2)
{int len1 = str1.length();int len2 = str2.length();int result = 0; //记录最长公共子串长度int c[len1+1][len2+1] ;int endPos = -1;for (int i = 0; i <= len1; i++){for( int j = 0; j <= len2; j++){if(i == 0 || j == 0){c[i][j] = 0;}else if (str1.at(i-1) == str2.at(j-1)){c[i][j] = c[i-1][j-1] + 1;result = max(c[i][j], result);if(result==c[i][j]) endPos = i;//记录最后一个点的位置}else{c[i][j] = 0;//重新计数}}}//print resultstring str="";if(endPos<=len1){str = str1.substr(endPos-result,result);}else{str = str2.substr(endPos-result,result);}cout<<"\n\nLongest Common Substring : "<<str<<endl;return result;
}
//对于最长公共子序列,只是在最后一个else里面放的是前两步的最大值
int lcs_squence(string str1, string str2)
{int len1 = str1.length();int len2 = str2.length();int c[len1+1][len2+1];vector<vector<string>> flag;initialVector(flag,len1+1);for (int i = 0; i <= len1; i++){for( int j = 0; j <= len2; j++){if(i == 0 || j == 0){c[i][j] = 0;flag[i].push_back("NULL");}else if (str1.at(i-1) == str2.at(j-1)){c[i][j] = c[i-1][j-1] + 1;flag[i].push_back("left_up");}else if(c[i - 1][j]>=c[i][j - 1]){c[i][j]=c[i - 1][j];flag[i].push_back("left");}else{c[i][j] = c[i][j - 1];flag[i].push_back("up") ;}}}//display(&c[0][0],str1,str2); //输出数组SubSequence(flag,str1,str2,str1.length(),str2.length());//cout<<c[len1][len2]<<endl;return c[len1][len2];
}void display(int *result,string str1,string str2)
{int len1 = str1.length();int len2 = str2.length();//输出表头for(int i=0; i<=len2; ++i){cout<<"\t"<<str2[i];}cout<<endl;//输出数组for(int i=0; i<=len1; ++i){cout<<str1[i]<<"\t";for(int j=0; j<=len2; ++j){cout<<*result<<"\t";result++;}cout<<endl;}}
//按照方向查找
void SubSequence(vector<vector<string>> &flag,string str1, string str2,int i,int j)
{if (i == 0 || j == 0)return;if (flag.at(i).at(j) == "left_up"){cout<<str2[j - 1]<<" ("<< i - 1<<" , "<< j - 1<<")"<<endl;//左前方SubSequence(flag,str1,str2,i - 1, j - 1);}else{if (flag.at(i).at(j) == "up"){SubSequence(flag,str1,str2,i, j - 1);}else{SubSequence(flag,str1,str2,i - 1, j);}}
}int main()
{string X = "";string Y = "";//输入getline(cin,X);getline(cin,Y);cout<<"\nFirst string:\n"<<X<<endl;cout<<"\nSecond string:\n"<<Y<<endl;cout << "Length of Longest Common Substring is " << lcs_string(X, Y)<<endl;cout << "Length of Longest Common Subsequence is " << lcs_squence(X, Y)<<endl;return 0;
}
参考引用
传送门 : 最长公共子序列
传送门 : 最长公共子序列(LCS)C++实现
传送门 : 最长公共子序列与最长公共子串
传送门 : 最长公共子序列。。
传送门 : 最长公共子序列。。大杂烩