前面我们已经写过关于一个字符串的最长回文子串(三层遍历,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;
}

 

posted on 2018-05-30 11:10  Mini_Coconut  阅读(412)  评论(0编辑  收藏  举报