动态规划实例(十三):最长公共子串(LCS)

    最长公共子序列 & 最长公共子串的区别:找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。而最长公共子序列则并不要求连续
    这两个都可以使用动态规划解决,但是思路不太一样。
    我们采用一个二维矩阵来记录中间的结果。这个二维矩阵怎么构造呢?直接举个例子吧:”bab”和”caba”(当然我们现在一眼就可以看出来最长公共子串是”ba”或”ab”)
             b  a  b
         c  0  0  0
         a  0  1  0
         b  1  0  1
         a  0  1  0
    我们看矩阵的斜对角线最长的那个就能找出最长公共子串。不过在二维矩阵上找最长的由1组成的斜对角线也是件麻烦费时的事,下面改进:当要在矩阵是填1时让它等于其左上角元素加1。
             b  a  b
         c  0  0  0
         a  0  1  0
         b  1  0  2
         a  0  2  0

这样矩阵中的最大元素就是 最长公共子串的长度。

具体实例及实现代码如下所示:

/**
 * @Title: LongestCommomSubString.java
 * @Package dynamicprogramming
 * @Description: TODO
 * @author peidong
 * @date 2017-6-13 上午8:41:48
 * @version V1.0
 */
package dynamicprogramming;

/**
 * @ClassName: LongestCommomSubString
 * @Description:最长公共子串
 * @date 2017-6-13 上午8:41:48
 *
 */
public class LongestCommomSubString {

    /**
     *
     * @Title: longestCommonSubString
     * @Description: 动态规划求解最长公共子串
     * @param str1
     * @param str2
     * @return
     * @return String
     * @throws
     */
    public static String longestCommonSubString(String str1, String str2){
        //创建变量保存公共子串,此处不能用String,需要改变
        StringBuilder sb = new StringBuilder();
        //边界条件判断
        if(str1 == null || str1.isEmpty() || str2 == null || str2.isEmpty())
            return "";

        //创建状态转移矩阵,保存子串长度
        int[][] tc = new int[str1.length()][str2.length()];
        //定义变量保存最长字符串长度
        int maxLen = 0;
        //定义变量保存最长子串起始位置
        int lastSubsBegin = 0;

        //构建状态转移矩阵
        for(int i = 0; i < str1.length(); i++){
            for(int j = 0; j < str2.length(); j++){
                if(str1.charAt(i) == str2.charAt(j)){
                    if(i == 0 || j == 0)
                        tc[i][j] = 1;
                    else
                        tc[i][j] = 1 + tc[i-1][j-1];
                    if(tc[i][j] > maxLen){
                        maxLen = tc[i][j];

                        //记录此时子串在str1中的起始位置
                        int thisBegin = i - tc[i][j] + 1;
                        //如果是同一个子串
                        if(lastSubsBegin == thisBegin)
                            sb.append(str1.charAt(i));
                        else{//不是同一个子串重新生成
                            lastSubsBegin = thisBegin;
                            sb = new StringBuilder();
                            sb.append(str1.substring(lastSubsBegin, i + 1));
                        }
                    }
                }
            }
        }
        return sb.toString();
    }
    /**
     * @Title: main
     * @Description: 测试用例
     * @param args
     * @return void
     * @throws
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        String str1 = "I love python!";
        String str2 = "love python I do";
        String str = longestCommonSubString(str1, str2);
        System.out.println("两字符串的最长公共子串为:" + str);
        System.out.println("最长公共子串的长度为:" + str.length());
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值