最长公共子串

/***********************************************************************
 *description:最长公共子串
 *            给定两个字符串str1和str2,返回两个字符串的最长公共子串
 *            如:str1=“1AB2345CD” str2=“12345EF”
 *                返回“2345”

 ***********************************************************************/

#include <iostream>
#include <string>
#include <vector>
using namespace std;

//方法1:时间复杂度O(M*N),空间复杂度O(M*N)
//经典动态规划问题,数组dp[M][N]
//dp[i][j]代表str1[i]和str2[j]当做公共子串最后元素的最大长度
//dp[i][0]:str1[i]==str2[0]时才为1,否则为0
//dp[0][j]:str1[0]==str2[j]时才为1,否则为0
//dp[i][j]:
//          1.str1[i]!=str2[j],dp[i][j]=0
//          2.str1[i]==str2[j],dp[i][j]=dp[i-1][j-1]+1
//得到dp之后,遍历找到最大的元素及其位置,然后str1的该位置向前索引即可。
string longestSharedSubStr_1(string str1, string str2)
{
    string res;
    int M = str1.size();
    int N = str2.size();
    if (M == 0 || N == 0)
        return res;

    vector<vector<int>> dp(M,N);

    for (int i = 0; i < M; i++)
    {
        dp[i][0] = 0;
        if (str1[i] == str2[0])
            dp[i][0] = 1;
    }
    for (int j = 0; j < N; j++)
    {
        dp[0][j] = 0;
        if (str1[0] == str2[j])
            dp[0][j] = 1;
    }
    for (int i = 1; i < M; i++)
    {
        for (int j = 1; j < N; j++)
        {
            if (str1[i] != str2[j])
                dp[i][j] = 0;
            else
                dp[i][j] = dp[i-1][j-1] + 1;
        }
    }
    int len = 0;
    int endIdx = 0;
    for (int i = 0; i < M - 1; i++)
    {
        for (int j = 0; j < N; j++)
        {
            if (dp[i][j] > len)
            {
                len = dp[i][j];
                endIdx = i;
            }
        }
    }
    return str1.substr(endIdx - len + 1, len);

}
//方法2:时间复杂度O(M*N),空间复杂度O(1)
//在方法1的基础上进行优化。
//每次计算dp[i][j]时,只和dp[i-1][j-1]相关,所以每次按斜线计算,只用一个变量空间。
//然后用个全局变量记录len和endIdx
string longestSharedSubStr_2(string str1, string str2)
{
    int M = str1.size();
    int N = str2.size();
    if (M == 0 ||  N == 0)
        return "";

    int len = 0;
    int endIdx = 0;
    int last = 0;

    int col = N -1;
    int row = 0;
    while (row < M)
    {
        last = 0;
        int i = row;
        int j = col;
        while (i < M && j < N)
        {
            if (str1[i] == str2[j])
            {
                last++;
            }
            if (last > len )
            {
                len = last;
                endIdx = i;
            }
            i++;
            j++;
        }
        if (col > 0)
            col--;
        else
            row++;
    }

    return str1.substr(endIdx - len + 1, len);

}

int main()
{
    string str1 = "1AB2345CD";
    string str2 = "12345EF";

    cout << longestSharedSubStr_2(str1, str2);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值