题解 | #公共子串计算#
公共子串计算
http://www.nowcoder.com/practice/98dc82c094e043ccb7e0570e5342dd1b
题目的主要信息:
查找两个字符串a,b中的最长公共子串的长度。
方法一:
枚举法。用maxLen暂存最长公共子串长度。枚举所有a中可能出现的子串,用find函数判断该子串是否在b中出现,如果在b中出现的话,比较该子串与已知的最长公共子串的长度,如果更长,则更新maxLen。枚举所有的子串用双重for循环,首先遍历一遍子串的起始位置,然后遍历一遍所有可能的长度。需要注意的是,当某个子串temp不在b中时,说明从这个位置开始,大于temp长度的子串都不可能在b中找到,因此可以结束当前循环,从下一个位置开始判断。枚举完所有子串后的maxLen就是最长公共子串长度。
具体做法:
#include<iostream>
#include<string>
#include<math.h>
using namespace std;
int main(){
string a,b;
while(cin>>a>>b){//输入两个字符串
int maxLen=0;
for(int i=0;i<a.size();i++){
for(int j=i;j<a.size();j++){
string temp=a.substr(i,j-i+1);//temp为a的子串
if(int(b.find(temp))<0){//若temp在b中没有出现,跳出当前循环,从下一个位置i开始找子串
break;
}else if(maxLen<temp.size()){//找到了更长的公共子串
maxLen=temp.size();
}
}
}
cout<<maxLen<<endl;
}
return 0;
}
复杂度分析:
- 时间复杂度:,两层for循环。
- 空间复杂度:,只用了常数空间。
方法二:
动态规划。动态数组dp[i][j]表示在b中以第i个字符结尾,a中以第j个字符结尾时的公共子串长度。,maxlen表示最长公共子串的长度。遍历一遍两个字符串:
- 如果b中第i和a中第j个字符相同,则在以i-1和j-1结尾的子串后面加上i、j一位仍然是子串,因此dp[i][j]=dp[i−1][j−1]+1。
- 如果b中第i和a中第j个字符不相同,则以他们结尾的子串不可能相同,dp[i][j]=0。
如果更新后的dp[i][j]比maxlen大,则更新最大子串信息。
具体做法:
#include <iostream>
#include <vector>
using namespace std;
int main(){
string a,b;
while (cin >> a >> b)
{
int maxLen = 0;
vector<vector<int>> dp(b.size()+1,vector<int>(a.size()+1,0));//动态数组,dp[i][j]表示b以第i个字符结尾,a以第j个字符结尾的公共子串的长度
for (int i = 1; i <= b.size(); ++i){
for (int j = 1; j <= a.size(); ++j){
if (b[i - 1] == a[j - 1]) {//b中第i个字符和a中第j个字符相同
dp[i][j] = dp[i - 1][j - 1] + 1;//前一个长度加一
}else {
dp[i][j] = 0;//如果第i个字符和第j个字符不同,则以他们结尾的子串不可能相同
}
if (maxLen < dp[i][j]) {//更新最大值
maxLen = dp[i][j];
}
}
}
cout << maxLen << endl;
}
return 0;
}
复杂度分析:
- 时间复杂度:,两层for循环,遍历一遍dp数组。
- 空间复杂度:,dp数组大小为mn。