最长公共子串---动态规划

最长公共子串问题
【题目】
给定两个字符串str1和str2,返回两个字符串的最长公共子串。
【举例】str1="1AB2345CD",str2="12345EF",返回"2345"。
首先需要生成动态规划表。生成大小为M×N的矩阵dp,行数为M,列数为N。
dp[i][j]的含义是,在必须把str1[i]和str2[j]当作公共子串最后一个字符的情况下,公共子串最长能有多长。
比如,str1="A1234B",str2="CD1234",
dp[3][4]的含义是在必须把str1[3](即’3')和str2[4](即’3')当作公共子串最后一个字符的情况下,
公共子串最长能有多长。这种情况下的最长公共子串为"123",所以dp[3][4]为3。
]再如,str1="A12E4B",str2="CD12F4",
dp[3][4]的含义是在必须把str1[3](即’E')和str2[4](即’F')当作公共子串最后一个字符的情况下,
公共子串最长能有多长。这种情况下根本不能构成公共子串,所以dp[3][4]为0。介绍了dp[i][j]的意义后,
接下来介绍dp[i][j]怎么求。
具体过程如下:
1.矩阵dp第一列即dp[0..M-1][0]。
对某一个位置(i,0)来说,如果str1[i]==str2[0],令dp[i][0]=1,否则令dp[i][0]=0。
比如str1="ABAC",str2[0]="A"。
dp矩阵第一列上的值依次为dp[0][0]=1,dp[1][0]=0,dp[2][0]=1,dp[3][0]=0。
2.矩阵dp第一行即dp[0][0..N-1]与步骤1同理。对某一个位置(0,j)来说,
如果str1[0]==str2[j],令dp[0][j]=1,否则令dp[0][j]=0。
3.其他位置按照从左到右,再从上到下来计算,dp[i][j]的值只可能有两种情况。
● 如果str1[i]!=str2[j],说明在必须把str1[i]和str2[j]当作公共子串最后一个字符是不可能的,令dp[i][j]=0。
● 如果str1[i]==str2[j],说明str1[i]和str2[j]可以作为公共子串的最后一个字符,
从最后一个字符向左能扩多大的长度呢?就是dp[i-1][j-1]的值,所以令dp[i][j]=dp[i-1][j-1]+1。
如果str1="abcde",str2="bebcd"。计算的dp矩阵如下:
           b   e   b   c   d
       a   0   0   0   0   0
       b   1   0   1   0   0
       c   0   0   0   2   0
       d   0   0   0   0   3
       e   0   1   0   0   0
    public static String getdp2(char[] str1,char[] str2){
        if(str1==null||str2==null||str1.length==0||str1.length==0){
            return "";
        }
        int m=str1.length;
        int n=str2.length;
        //dp[i][j]对应,如果str1[i]==str2[j],以str1[i]为最后一个字符的情况下的最长公共子串,否则为0
        int[][] dp=new int [m][n];
        //初始化dp[0][0]
        dp[0][0]=(str2[0]==str1[0])?1:0;
        //初始化第一行
        for (int i = 1; i < n; i++) {
            if(str1[0]==str2[i]){
                dp[0][i]=1;
            }
        }
        //初始化第一列
        for (int i = 1; i < m; i++) {
            if(str2[0]==str1[i]){
                dp[i][0]=1;
            }
        }
        //计算dp[i][j]
        for (int i = 1; i < m; i++) {
            for (int j = 1; j <n; j++) {
                if(str1[i]==str2[j]){
                    dp[i][j]=dp[i-1][j-1]+1;
                }
            }
        }
        //以上可以得到一个二维数组dp

        int endIndex=0;
        int max=0;
        //然后遍历数组获取最长公共子串

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if(dp[i][j]>max){
                    endIndex=i;
                    max=dp[i][j];
                }
            }
        }
        String result=String.copyValueOf(str1).substring(endIndex-max+1, endIndex+1);

        return result;
    }

测试:

    public static void main(String[] args) {
        //String s1="1a2c3d4b56";
        //String s2="b1d23ca45b6a";

        String s1="1ab2345cd";
        String s2="12345ef";
        char[] str1=s1.toCharArray();
        char[] str2=s2.toCharArray();
        //System.out.println(getdp(str1, str2));
        System.out.println(getdp2(str1, str2));
    }

2345

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值