最长公共子串

在这里插入图片描述

暴力和动态规划均可做
主要是了解动态规划怎么做;
我们发现,在相同开端的子串的比较中,有很多事重复动作。比如在比较以i,j分别为起点的子串时,有可能会进行i+1和j+1以及i+2和j+2位置的字符的比较。而以i+1,j+1分别为起点的子串时,这些字符又被比较了一次。也就说该问题有非常相似的子问题,而子问题之间又有重叠,这就给动态规划法创造了契机。

暴力解法是以子串开端开始寻找,现在换个思路,以相同子串的字符结尾来利用动态规划法。

假设两个字符串分别为A、B,A[i]和B[j]分别表示其第i和j个字符,再假设K[i,j]表示以A[i]和B[j]结尾的子串的最大长度。那么A,B分别再向下走一个字符,我们可以推断出K[i+1,j+1]与K[i,j]之间的关系,如果A[i] == B[j],那么K[i+1,j+1] = K[i,j] + 1;否则K[i+1,j+1] =0。而如果A[i+1]和B[j+1]相同,那么就只要在以A[i]和B[j]结尾的最长相同子串之后分别添上这两个字符即可,这样就可以让长度增加一位,综上所述,就是K[i+1,j+1] = (A[i] == B[j] ? K[i,j] + 1 : 0)的关系。

由上述K[i+1,j+1] = (A[i] == B[j] ? K[i,j] + 1 : 0)的关系,想到了使用二维数组来存储两个字符串之间的相同子串关系,因为K[i+1,j+1] = (A[i+1] == B[j+1] ? K[i,j] + 1 : 0)关系,只计算二维数据的最上列和最左列数值即可,其他数值通过K[i+1,j+1] = (A[i+1] == B[j+1] ? K[i,j] + 1 : 0)可得。

动态规划解法:

#include<bits/stdc++.h>
using namespace std;

int dp[1005][1005];

int main()
{
    string s1,s2;
    while(cin >> s1 >> s2){
        int len1 = s1.size();
        int len2 = s2.size();
        if(len1 > len2){
            swap(s1,s2);
            swap(len1,len2);
        }
        memset(dp,0,sizeof(dp));
        int MAX = 0;
        for(int i = 0;i < len1;++i){
            dp[i][0] = (s1[i] == s2[0]) ? 1 : 0;
        }
        for(int j = 1;j < len2;++j){
            dp[0][j] = (s1[0] == s2[j]) ? 1 : 0;
        }
        int start = 0;
        for(int i = 1;i < len1;++i){
            for(int j = 1;j < len2;++j){
                if(s1[i] == s2[j]){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                if(dp[i][j] > MAX){
                    MAX = dp[i][j];
                    start = i - MAX + 1;
                }
            }
        }
        cout << s1.substr(start,MAX) << endl;
    }
    return 0;
}

暴力解法:

#include<bits/stdc++.h>
using namespace std;
 
int main()
{
    string s1,s2;
    while(cin >> s1 >> s2){
        int len1 = s1.size();
        int len2 = s2.size();
        if(len1 > len2){
            swap(s1,s2);
            swap(len1,len2);
        }
        int MAX = 0;
        string ans;
        for(int i = 0;i < len1;++i){
            for(int j = 0;j < len2;++j){
                if(s1[i] == s2[j]){
                    int cnt = 1;
                    int ii = i,jj = j;
                    while(i + 1 < len1 && j + 1 < len2 && s1[++ii] == s2[++jj]){
                        cnt++;
                    }
                    if(MAX < cnt){
                        MAX = cnt;
                        ans = s1.substr(i,cnt);
                    }
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值