最长公共子序列25-01-14

题目 #

题目描述 #

给你一个序列X和另一个序列Z,当Z中的所有元素都在X中存在,并且在X中的下标顺序是严格递增的,那么就把Z叫做X的子序列。 例如:Z=是序列X=的一个子序列,Z中的元素在X中的下标序列为<1,2,4,6>。 现给你两个序列X和Y,请问它们的最长公共子序列的长度是多少?

输入描述 #

输入包含多组测试数据。每组输入占一行,为两个字符串,由若干个空格分隔。每个字符串的长度不超过100。

输出描述 #

对于每组输入,输出两个字符串的最长公共子序列的长度。

输入示例 #

abcfbc abfcab programming contest abcd mnp

输出示例 #

4 2 0

解答 #

1 动态规划求解 #

import java.io.*;
import java.util.*;
  
public class Main{
    public static int getMax(String a,String b,int aLen,int bLen){
        char[] aArr=a.toCharArray();
        char[] bArr=b.toCharArray();
        int[][] dp=new int[aLen+1][bLen+1];
        for(int i=0;i<aLen+1;i++){
            dp[i][0]=0;
        }
        for(int i=0;i<bLen+1;i++){
           dp[0][i]=0; 
        }
        for(int i=1;i<aLen+1;i++){
            for(int j=1;j<bLen+1;j++){
                int temp1=0;
                if(aArr[i-1]==bArr[j-1]){
                    temp1=dp[i-1][j-1]+1;
                }
                dp[i][j]=Math.max(Math.max(dp[i-1][j],dp[i][j-1]),temp1);
            }
        }
        return dp[aLen][bLen];
    }
    public static void main(String[] args) throws IOException{
        BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out=new PrintWriter(System.out);
        String line;
        while((line=in.readLine())!=null){
            String[] arr=line.split(" ");
            String a=arr[0];
            String b=arr[1];
            int aLen=a.length();
            int bLen=b.length();
            out.println(getMax(a,b,aLen,bLen));
        }
        out.flush();
    }
}

使用动态规划进行求解 核心的问题在于状态转移方程的设计 对于两个字符串,其实比较的主要内容是dp[i][j]中i和j对应的字符是否相同

  • 如果相同的话,其转移方程是dp[i-1][j-1]+1
  • 如果不相同,其只可能从两个方向转过来:
    • dp[i-1][j]转变
    • dp[i][j-1]转变

实际上就是这三者进行比较,取最大值即可

dp[i][j]=max{dp[i1][j1]+1,dp[i1][j],dp[i][j1]. \text{dp}[i][j] = \max\left\{\begin{aligned}&\text{dp}[i-1][j-1] + 1, \\&\text{dp}[i-1][j], \\&\text{dp}[i][j-1].\end{aligned}\right.

复杂度 #

时间复杂度: O(n * m),其中 n 和 m 分别为 text1 和 text2 的长度 空间复杂度: O(n * m)