最长公共子序列 最长公共子串(未)

最长公共子序列 最长公共子串

字符串中常见的用到动态规划的题目,求最长公共子序列和最长公共子串。

1. 最长公共子序列

1.1 求最长公共子序列的值

子串和子序列是不同的,子串要求连续。
《算法导论》第15章动态规划就是讲最长公共子序列。参考七月算法官网的LCS的视频,讲得很清晰。
得出下面的递推公式:
这里写图片描述
显然属于动态规划的题目。

int lcs(string str1, string str2) {
    int len1 = str1.length();
    int len2 = str2.length();
    int n = len1 + 1;
    int m = len2 + 1;
    int i, j;
    vector<vector<int> > res(n, vector<int>(m));
    for (j = 0; j < m; j ++)
        res[0][j] = 0;
    for (i = 0; i < n; i ++)
        res[i][0] = 0;
    for (i = 1; i < n; i ++)
        for (j = 1; j < m; j ++) {
            if (str1[i - 1] == str2[j - 1]) {
                res[i][j] = res[i - 1][j - 1] + 1;
            } else {
                res[i][j] = max(res[i - 1][j], res[i][j - 1]);
            }
        }
    return res[n - 1][m - 1];
}

自底向上的动态规划,时间复杂度是O(N*M),空间复杂度分析O(N*M),因为求res二维数组中的每一个值。
如果只是求最长公共子序列的长度,空间复杂度是可以优化的。

参考:
[1] http://blog.csdn.net/crayondeng/article/details/14442645

1.2 返回最长公共子序列

如果仅仅是求长公共子序列的值,上述解法可以。如果要求返回的是最长公共子序列,需要维护一个表direc来构造二维数组。
代码如下:

int lcs(string str1, string str2, vector<vector<int> > &direc) {
    int len1 = str1.length();
    int len2 = str2.length();
    int n = len1 + 1;
    int m = len2 + 1;
    int i, j;
    vector<vector<int> > res(n, vector<int>(m));
    for (j = 0; j < m; j ++)
        res[0][j] = 0;
    for (i = 0; i < n; i ++)
        res[i][0] = 0;
    for (i = 1; i < n; i ++)
        for (j = 1; j < m; j ++) {
            if (str1[i - 1] == str2[j - 1]) {
                res[i][j] = res[i - 1][j - 1] + 1;
                direc[i][j] = 0;
            } else if (res[i - 1][j] > res[i][j - 1]){
                res[i][j] = res[i - 1][j];
                direc[i][j] = 1;
            } else {
                res[i][j] = res[i][j - 1];
                direc[i][j] = -1;
            }
        }
    return res[n - 1][m - 1];
}
void PrintLCS(string str1, vector<vector<int> > direc, int i, int j) {
    if (i == 0 || j == 0)
        return;
    if (direc[i][j] == 0) {
        PrintLCS(str1, direc, i - 1, j - 1);
        /* 第i行元素对应的str1中是i-1的下标 */
        cout << str1[i - 1];
    } else if (direc[i][j] == 1) {
        PrintLCS(str1, direc, i - 1, j);
    } else {
        PrintLCS(str1, direc, i, j - 1);
    }
}

按照表direc构造最长公共子序列,是逆序的,所以我们可以用递归过程按正确的顺序打印出X和Y的一个LCS。

参考:
[1] 七月算法的PPT
[2]《算法导论》第15章动态规划
[3] http://blog.csdn.net/hackbuteer1/article/details/6686925

2. 最长公共子串

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值