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

1. 问题描述

最长公共子序列:常用于解决字符串的相似度,是指在母串中都出现过并且出现顺序与母串保持一致的子串,不要求连续性。
最长公共子串:是指在母串中连续出现的子串。

例如:
cnblogs
belong
最长公共子序列为blog,最长公共子串为lo

2. 动态规划——最长公共子序列

假设 Z=<z1,z2,,zk> 是母串 X Y 的最长公共子序列LCS,那么

  • 如果 xm=yn ,则 zk=xm=yn ,并且 Zk1 Xm1 Yn1 的LCS;
  • 如果 xmyn ,则 Zk Xm1 Yn 或者 Xm Yn1 的LCS;

用二维数组 dp[i][j] 记录串 x1,x2,,xi y1,y2,,yj 的LCS长度,则可得到状态转移方程:
dp[i][j]=0,dp[i1][j1]+1max(dp[i][j1],dp[i1][j]) if i=0 || j=0 if i,j>0 && xi=yj if i,j>0 and xi̸yj

代码实现

//最长公共子序列
    int LongestCommonSubsequence(string a, string b){
        int alen = a.length();
        int blen = b.length();
        if(alen <= 0 || blen<= 0)
            return 0;

        int dp[alen+1][blen+1];
        for(int i = 0; i <= alen; ++i)
            for(int j = 0; j <= blen; ++j){
                if(i == 0 || j == 0)
                    dp[i][j] = 0;
                else if(a[i-1] == b[j-1])
                    dp[i][j] = dp[i-1][j-1] +1;
                else
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            }
        return dp[alen][blen];
    }

3. 动态规划——最长公共子串

最长公共子串是最长公共子序列的一种特殊情况,考虑到最长公共子串的连续性,定义状态转移方程如下:
dp[i][j]=0,dp[i1][j1]+10 if i=0 || j=0 if i,j>0 && xi=yj if i,j>0 and xi̸yj
最长公共子串的长度为 max(c[i,j]),i(1,,m),j(1,,n)

代码实现

//最长公共子串
    int LongestCommonSubstring(string a, string b){
        int alen = a.length();
        int blen = b.length();
        if(alen <= 0 || blen<= 0)
            return 0;

        int dp[alen+1][blen+1];
        int result = 0;
        for(int i = 0; i <= alen; ++i)
            for(int j = 0; j <= blen; ++j){
                if(i == 0 || j == 0)
                    dp[i][j] = 0;
                else if(a[i-1] == b[j-1]){
                    dp[i][j] = dp[i-1][j-1] +1;
                    result = max(result, dp[i][j]);
                }
                else
                    dp[i][j] = 0;
            }
        return result;
    }

4. 添加/删除最少字符使得字符串整体为回文字符串

解题思路:

如果能在母串S中找到最长的子序列L,并且这个子序列是回文,那么插入ans = strlen(s) - strlen(L)个字符就能使得原串成为回文字符串。

问题转为求一个字符串的最长回文子序列,这个问题可以使用最长公共子序列的解法,解法如下:
1.求S的逆序串 S’,;
2.求S和S’的最长公共子序列L,L即为S的最长回文子序列;
3.ans = strlen(s) - strlen(L)。

例如: S = abca 那么 S’ = acba ,那么L = aba 那么答案就是1。即 a‘c’bca。其中’c’为插入的字符。

代码实现

//添加最少字符使得字符串整体为回文字符串
    int getPalindrome(string str){
        int len = str.length();
        if(len <= 0)
            return 0;

        //得到母串的逆序字符串
        string invertedstr;
        for(int i = len - 1; i >= 0; --i){
            string temp {str[i]};
            invertedstr.append(temp);
        }

        //得到母串与其逆序字符串的最长公共子序列长度
        int lcslen = LongestCommonSubsequence(str, invertedstr);

        return len - lcslen;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值