问题描述

  • 对于两个字符串,请设计一个时间复杂度为O(m*n)的算法(这里的m和n为两串的长度),求出两串的最长公共子串的长度。这里的最长公共子串的定义为两个序列U1,U2,..Un和V1,V2,...Vn,其中Ui + 1 == Ui+1,Vi + 1 == Vi+1,同时Ui == Vi。
  • 输入: "1AB2345CD",9,"12345EF",7
  • 返回: 4
  • 解释: 两个字符串都有 "2345" 子串, 并且子串在两个字符串内连续

题解思路

  • 状态方程: F(i, j) 表示当A[i] == B[j] 并且把A[i]和B[j]当做是公共子串的最后一个字符所表示的最大长度, 由于是要连续的最大子串长度, 所以 F(i, j) = F(i-1, j-1) + 1;
  • 初始条件
    • 初始化行: 当B[i] == A[0], F(0, i) = 1
    • 初始化列: 当A[i] == B[0], F(i, 0) = 1
  • 已经有了连续子串的最大长度, 要得到最长连续子串, 根据这个最大长度所处的位置向前递推最大长度即可

代码实现

int findLongest(std::string A, int n, std::string B, int m) {
    if(n <= 0 || m <= 0) {
        return 0;
    }

    std::vector<std::vector<int>> dp(n, std::vector<int>(m, 0));
    int res = 0;

    // init row
    for(int i = 0; i < m; ++i) {
        if(A[0] == B[i]) {
            dp[0][i] = 1;
        }
    }

    for(int i = 0; i < n; ++i) {
        if(A[i] == B[0]) {
            dp[i][0] = 1;
        }
    }

    for(int i = 1; i < n; ++i) {
        for(int j = 1; j < m; ++j) {
            if(A[i] == B[j]) {
                dp[i][j] = dp[i-1][j-1] + 1;
                res = std::max(res, dp[i][j]);
            }
        }
    }

    return res;
}