最长公共字符串问题

//1.返回str1和str2的最长公共子序列
    public int[][] getdp(char[] ch1, char[] ch2){
        int[][] dp = new int[ch1.length][ch2.length];
        dp[0][0] = ch1[0] == ch2[0] ? 1 : 0;
        for(int i = 1; i < ch1.length; i++){
            dp[i][0] = Math.max(dp[i-1][0], ch1[i] == ch2[0] ? 1 : 0);
        }

        for(int i = 1; i < ch2.length; i++){
            dp[0][i] = Math.max(dp[0][i-1], ch1[0] == ch2[1] ? 1 : 0);
        }

        for(int i = 1; i < ch1.length; i++){
            for(int j = 1; j < ch2.length; j++){
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                if(ch1[i] == ch2[j]){
                    dp[i][j] = Math.max(dp[i][j], dp[i-1][j-1]+1);
                }
            }
        }
        return dp;
    }

    //反推回去,找出相同的字符
    public String lcse(String str1, String str2){
        if(str1 == null || str2 == null || str1.equals("") || str2.equals("")){
            return "";
        }
        char[] ch1 = str1.toCharArray();
        char[] ch2 = str2.toCharArray();
        int[][] dp = getdp(ch1, ch2);
        int n = ch1.length-1;
        int m = ch2.length-1;
        int[] res = new int[dp[n][m]];
        int index = res.length-1;
        while(index >= 0){
            //说明dp[n][m]来源于dp[n-1][m]
            if(n > 0 && dp[n][m] == dp[n-1][m]){
                n--;
            //说明dp[n][m]来源于dp[n][m-1]
            } else if(m > 0 && dp[n][m] == dp[n][m-1]){
                m--;
            } else {
                //说明dp[n][m]来源于dp[n-1][m-1]+1此时ch[n] == ch[m]
                res[index--] = ch1[n];
                n--;
                m--;
            }
        }
        return String.valueOf(res);
    }

    //2.进阶,返回两个字串的最长连续公共子串
    //对于此问题与上述问题相似,只不过在对比每个ch[i] ch[j]的过程中,相等则说明该字符可以
    //作为公共子串的最后一个字符,不相等则dp[i][j] = 0,以该字符开头的相等字符为0
    public int[][] getdp2(char[] ch1, char[] ch2){
        int[][] dp = new int[ch1.length][ch2.length];
        dp[0][0] = ch1[0] == ch2[0] ? 1 : 0;
        for(int i = 1; i < ch1.length; i++){
            dp[i][0] = ch1[i] == ch2[0] ? 1 : 0;
        }

        for(int i = 1; i < ch2.length; i++){
            dp[0][i] = ch1[0] == ch2[1] ? 1 : 0;
        }

        for(int i = 1; i < ch1.length; i++){
            for(int j = 1; j < ch2.length; j++){
                if(ch1[i] == ch2[j]){
                    dp[i][j] = dp[i-1][j-1] + 1;
                }
            }
        }
        return dp;
    }

    public String lcse2(String str1, String str2){
        if(str1 == null || str2 == null || str1.equals("") || str2.equals("")){
            return "";
        }
        char[] ch1 = str1.toCharArray();
        char[] ch2 = str2.toCharArray();
        int[][] dp = getdp2(ch1, ch2);
        int end = 0;
        int max = 0;
        for(int i = 0; i < ch1.length; i++){
            for(int j = 0; j < ch2.length; j++){
                if(dp[i][j]  > max){
                    end = i;
                    max = dp[i][j];
                }
            }
        }
        return str1.substring(end-max+1, end+1);
    }

    //以上可以把空间复杂度简化为o(1)
    //因为每个i,j都需要的是i-1,j-1
    //所以只需要记录每条斜线上的最大长度和最大长度处的index即可
    //该解法是在上述dp中建立模型后的优化。
    public String lcse3(String str1, String str2){
        if(str1 == null || str2 == null || str1.equals("") || str2.equals("")){
            return "";
        }
        char[] ch1 = str1.toCharArray();
        char[] ch2 = str2.toCharArray();
        int end = 0;
        int max = 0;
        int row = 0;
        int col = ch2.length - 1;
        while(row < ch1.length){
            int i = row;
            int j = col;
            int len = 0;
            while(i < ch1.length && j < ch2.length){
                if(ch1[i] == ch2[j]){
                    len++;
                } else {
                    len = 0;
                }
                if(len > max){
                    end = i;
                    max = len
                }
                i++;
                j++
            }
            if(col > 0){
                col--;
            } else {
                row++;
            }
        }
        return str1.substring(end-max+1, end+1);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值