BM65-最长公共子序列(二)

题目

给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列。

数据范围:0≤∣str1∣,∣str2∣≤2000。

要求:空间复杂度 O(n^2),时间复杂度 O(n^2)。

示例1

输入:"1A2C3D4B56","B1D23A456A"

返回值:"123456"

示例2

输入:"abc","def"

返回值:"-1"

示例3

输入:"abc","abc"

返回值:"abc"

示例4

输入:"ab",""

返回值:"-1"


思路

  • 需要明确状态:当前处理到的 s1 和 s2 分别的第 i 和第 j 个字符。
  • 定义状态数组:dp[i][j]表示从左到右,当处理到s1的第i个元素和s2的第j个元素时的公共子序列。
  • 状态初始化:即当i==0或j==0的情况,dp[i][j]为"",因为空字符串没有公共子序列。
  • 状态转移:
    • 当前字符相等,则添加结果,i 和 j 指针右移,状态转移方程为:dp[i][j] = dp[i-1][j-1] + s1.charAt(i-1)
    • 当前字符不相等,则还需要分两种情况,取长度较长的情况,状态转移方程为: dp[i][j] = dp[i-1][j].length() > dp[i][j-1].length() ? dp[i-1][j] : dp[i][j-1]

代码

import java.util.*;

public class Solution {
    /**
     * longest common subsequence
     * @param s1 string
     * @param s2 string
     * @return string
     */
    public String LCS (String s1, String s2) {
        //子序列:不连续,但相对顺序不能发生改变
        //dp[i][j]表示s1的[0,i]区间以及s2的[0,j]区间内,长度最长的公共子序列

        //1.创建dp表
        int len1 = s1.length(), len2 = s2.length();
        String[][] dp = new String[len1 + 1][len2 + 1];

        //2.初始化
        //当i==0或j==0的情况,dp[i][j]为"",因为空字符串没有公共子序列
        for (int i = 0; i <= len1; i++) {
            // j == 0
            dp[i][0] = "";
        }
        for (int j = 0; j <= len2; j++) {
            // i == 0
            dp[0][j] = "";
        }

        //3.填表
        for (int i = 1; i <= len1; i++) {
            for (int j = 1; j <= len2; j++) {
                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];
                }
            }
        }

        //4.返回值
        return dp[len1][len2] == "" ? "-1" : dp[len1][len2];
    }
}

 

你可能感兴趣的:(面试必刷TOP101,java,算法,动态规划)