BM65 最长公共子序列(二)
中等 通过率:30.49% 时间限制:3秒 空间限制:256M
知识点:动态规划
描述
给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列
数据范围:0≤∣str1∣,∣str2∣≤20000≤∣str1∣,∣str2∣≤2000
要求:空间复杂度 O(n2)O(n2) ,时间复杂度 O(n2)O(n2)
示例1
输入:
"1A2C3D4B56","B1D23A456A"
返回值:
"123456"
示例2
输入:
"abc","def"
返回值:
"-1"
示例3
输入:
"abc","abc"
返回值:
"abc"
示例4
输入:
"ab",""
返回值:
"-1"
求最长公告子序列:用到的方法就是动态规划
运用动态规划(Dynamic Programming)的思想来解决最长公共子序列问题。动态规划的核心在于将原问题分解为多个子问题,通过求解子问题并保存其结果,避免重复计算,从而提高算法效率。具体到这个问题,会创建一个二维数组 dp 来存储子问题的解,其中 dp[i][j] 代表 s1 的前 i 个字符和 s2 的前 j 个字符的最长公共子序列。
核心部分:
for(int i =0;i<=n1;i++){
for(int j=0;j<=n2;j++){
if(i==0 || j==0){
dp[i][j] = "";
}else if (s1.charAt(i-1) == s2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1]+s1.charAt(i-1);
}else{
dp[i][j]=dp[i-1][j].length()>=dp[i][j-1].length()?dp[i-1][j]:dp[i][j-1];
}
}
}
使用两层嵌套的 for 循环来填充 dp 数组:
- 边界情况:当
i或j为 0 时,意味着其中一个字符串为空,此时最长公共子序列为空字符串,所以dp[i][j] = ""。 - 字符相等情况:当
s1的第i - 1个字符和s2的第j - 1个字符相等时,说明这个字符可以作为公共子序列的一部分。因此,dp[i][j]等于dp[i - 1][j - 1]加上这个相等的字符。 - 字符不相等情况:当
s1的第i - 1个字符和s2的第j - 1个字符不相等时,需要比较dp[i - 1][j]和dp[i][j - 1]的长度,取较长的那个作为dp[i][j]的值。
最后,检查 dp[n1][n2] 是否为空字符串。如果为空,说明两个字符串没有公共子序列,返回 -1;否则返回 dp[n1][n2],即 s1 和 s2 的最长公共子序列。
运行代码:
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* longest common subsequence
* @param s1 string字符串 the string
* @param s2 string字符串 the string
* @return string字符串
*/
public String LCS (String s1, String s2) {
if(s1.length() == 0 || s2.length()==0){
return "-1";
}
int n1 = s1.length();
int n2 = s2.length();
String[][] dp = new String[n1+1][n2+1];
for(int i =0;i<=n1;i++){
for(int j=0;j<=n2;j++){
if(i==0 || j==0){
dp[i][j] = "";
}else if (s1.charAt(i-1) == s2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1]+s1.charAt(i-1);
}else{
dp[i][j]=dp[i-1][j].length()>=dp[i][j-1].length()?dp[i-1][j]:dp[i][j-1];
}
}
}
return dp[n1][n2].equals("")?"-1":dp[n1][n2];
}
}

793

被折叠的 条评论
为什么被折叠?



