前面我们已经写过关于一个字符串的最长回文子串(三层遍历,DP,Manacher法)以及无重复字符的最长子串(unorder_map或者记录字符的最后出现位置),今天我们总结下两个字符串的一个最长操作——最长公共连续子串。最重要的是连续。
(1)我们可以首先用最基本的循环遍历来求解,求解以第一个字符串的每个字符为首的公共连续子串的长度,这里注意有可能会存在多个以其为首的子串,这里在第一个子串结束后,要接着遍历到结尾,说不定后面会继续出现一个连续子串。
#include <iostream> using namespace std; int getlongest(string s,string p) { if(s.empty()||p.empty()) return 0; int longest=0; for(int i=0;i<s.size();i++) for(int j=0;j<p.size();j++) { if(s[i]==p[j]) { int temp1=i,temp2=j; int count=1; while(temp1++<s.size()-1 && temp2++<p.size()-1) { if(s[temp1]==p[temp2]) count++; else break; } longest=longest<count ? count : longest; } } return longest; } int main() { string s="adfff",p="adf"; cout<< getlongest(s,p)<<endl; return 0; }
(2)还有一种DP的方法,数组的存储含义特别重要,定义不好的数组,会造成极其复杂的转化方程,这里我们定义dp[i][j]代表以s[i]和s[j]为公共子串的最后一个字符时的最长公共连续子串的长度。边界是dp[0][0]=0,转换方程是dp[i-1][j-1]如果s[i]=p[j],那么dp[i][j]=dp[i-1][j-1]+1;如果s[i]!=p[j],以其为结尾的最长公共子串为0。
注意这里dp[i][j]已经不是我们想要的最长公共子串长度了,它代表的是要以s[i]和p[j]为结尾的公共子串的最大长度。所以我们中间要注意存储最长的公共子串长度
int main() { string s1,s2; getline(cin, s1); getline(cin, s2); int len1 = s1.length(); int len2 = s2.length(); vector<vector<int>> dp(len1+1,vector<int>(len2+1)); for(int i=0; i<=len1; i++) { for(int j=0; j<=len2; j++) { dp[i][j] = 0; } } int res = 0; for(int i=1; i<=len1; i++) { for(int j=1; j<=len2; j++) { if(s1[i-1]==s2[j-1]) { dp[i][j] = dp[i-1][j-1]+1; res = res > dp[i][j] ? res : dp[i][j]; } else dp[i][j] = 0; } } cout <<res << endl; return 0; }