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

1.最长公共子序列(不用连续)

在这里插入图片描述

这个方法是求长度的,返回值是int

class Solution {
    public int longestCommonSubsequence(String str1, String str2) {
        if(str1.length()==0||str2.length()==0)
            return 0;

        int rows=str1.length();
        int colomns=str2.length();
        int[][] dp=new int[rows][colomns];//dp[i][j]表示strs1[0...i]和str2[0...j]的最长公共子序列长度
        //初始化dp[0][0]
        if(str1.charAt(0)==str2.charAt(0))//当两个字符串的第一个字符相等那么就赋值为1,不等就0
            dp[0][0]=1;
        else
            dp[0][0]=0;

        for(int j=1;j<colomns;j++)//初始化第一行
            dp[0][j]=Math.max(dp[0][j-1],str2.charAt(j)==str1.charAt(0)?1:0);

        for(int i=1;i<rows;i++)//初始化第一列
            dp[i][0]=Math.max(dp[i-1][0],str1.charAt(i)==str2.charAt(0)?1:0);

        //接下来就是dp[i][j]的普通情况了
        //看到下图的(L,L)位置,那么该位置可以从什么位置得到呢
        //因为(L,L)位置是str1[1]=str2[1],所以可以从(A,A)位置得到,取(A,A)位置的值+1,即是子序列A和子序列A构成的最大公共子序列长度
        for(int i=1;i<rows;i++){
            for(int j=1;j<colomns;j++){
                if(str1.charAt(i)==str2.charAt(j)){//依赖于左上角
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                else{//依赖于正上方和左方的值
//是因为要找的是最长公共子序列,所以当两个不相同时,要保持前面所得出的结果,所以选两者较大的
                    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }//意义是:例如(L,C)这个位置他们对应的字符不相等所以只能去取前面一个状态的dp值
                //【(L,L)意思是子序列AL和子序列AL构成的最大公共子序列长度】
                //【(A,L)意思是子序列A和ALC构成的最大公共子序列长度】
            }
        }
        return dp[rows-1][colomns-1];
    }
}
//初始化第一行就是str1的第一个字符串与str2整串相比,所以最大公共子序列只能1,dp[0][j]为1的话那么dp[0][j+1]后面的都是1
//第一列也一个道理
//            str2
//          A     L    C     H     E      M      I    S    T
//str1  A   1     1    1     1     1      1      1    1    1

//      L   1     2    2     2     2      2      2    2    2

//      G   1 

//      O   1
//
//      R   1 
//
//      I   1
//          
//      T   1
//
//      H   1
//
//      M   1

//      S   1

这个方法是求最长子串的,返回值是String

    public String lcse(String str1,String str2){
        
        int rows=str1.length();
        int coloums=str2.length();
        if(rows==0||coloums==0)
            return "";
        
        int[][] dp=getdp(str1,str2);//根据上面求最大子序列长度的过程的dp数组
        
        int i=rows-1;//作为str1的下标
        int j=coloums-1;//作为str2的下标
        char[] answer=new char[dp[i][j]];//长度为dp[i][j]的长度
        
        int index=answer.length-1;//指向answer数组的下标,初始指向末端位置
        while(index>=0){
            if(j>0&&dp[i][j]==dp[i][j-1]){//想一想,此处的dp是怎么来的,我们可以再看看上面求最大长度的过程:
                // 两个字符串对应的字符不相等时需要取舍正上方和正左方的dp值dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                j--;//往左移动
            }
            else if(i>0&&dp[i][j]==dp[i-1][j]){
                i--;
            }
            else{//而这里:就是当前的dp值比它上方的和左方的dp值都要大,那意味着当前的dp值对应的字符一定是属于最长公共子序列里面的,是由它左上方的斜对角的dp值+1得来的
                answer[index]=str1.charAt(i);
                index--;
                i--;
                j--;
            }
        }
        return String.valueOf(answer);
    }

2.最长公共子串(需要连续)

在这里插入图片描述

这个方法是求长度的

public class Solution {//返回最大长度
    public String LCS (String str1, String str2) {
        int rows=str2.length();
        int coloums=str1.length();
        int[][] dp=new int[rows][coloums];
        int answer=0;
        for(int i=0;i<coloums;i++)//初始化第一行,
            //遇到两个字符相关等就为1,不等就是0
           dp[0][i]=(str2.charAt(0)==str1.charAt(i)?1:0);
        
        for(int j=0;j<rows;j++)//初始化第一列
            //跟初始化第一行的逻辑一样
            dp[j][0]=(str1.charAt(0)==str2.charAt(j)?1:0);
        
        for(int i=0;i<rows;i++){//状态转移递推
            for(int j=0;j<coloums;j++){
                if(str2.charAt(i)==str1.charAt(j))
                    dp[i][j]=dp[i-1][j-1]+1;
                answer=Math.max(answer,dp[i][j]);
            }
        }
        return answer;
    }
}

这个是求对应的最长公共子串的

import java.util.*;
public class Solution {//返回对应子串
    public String LCS (String str1, String str2) {
        int rows=str2.length();
        int coloums=str1.length();
        int[][] dp=new int[rows][coloums];
        int answer=0;//用于记录最长的子串长度
        int lastIndex=0;//用于子串记录最长时str1的下标
        for(int i=0;i<coloums;i++)//初始化第一行,
            //遇到两个字符相关等就为1,不等就是0
           dp[0][i]=(str2.charAt(0)==str1.charAt(i)?1:0);
        
        for(int j=0;j<rows;j++)//初始化第一列
            //跟初始化第一行的逻辑一样
            dp[j][0]=(str1.charAt(0)==str2.charAt(j)?1:0);
        
        int row=0;
        int coloum=0;
        for(row=1;row<rows;row++){//状态转移递推
            for(coloum=1;coloum<coloums;coloum++){
                if(str2.charAt(row)==str1.charAt(coloum)){
                    dp[row][coloum]=dp[row-1][coloum-1]+1;
                    if(answer<dp[row][coloum]){
                        answer=dp[row][coloum];
                        lastIndex=coloum;
                    }
                    
                }
            }
        }
        return str1.substring(lastIndex-answer+1,lastIndex+1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值