牛客 BM65 最长公共子序列(二) 【动态规划】

该文章介绍了一种使用动态规划解决两个字符串的最长公共子序列(LCS)问题的方法。通过建立二维数组并初始化,然后逐个比较字符串中的字符,确定每个位置的最大长度。最终找到最长公共子序列的长度和具体序列。算法的时间和空间复杂度均为O(n^2)。
摘要由CSDN通过智能技术生成

描述

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

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

要求:空间复杂度 O(n2,时间复杂度 O(n2)

示例1

输入:

"1A2C3D4B56","B1D23A456A"

返回值:

"123456"

示例2

输入:

"abc","def"

返回值:

"-1"

示例3

输入:

"abc","abc"

返回值:

"abc"

示例4

输入:

"ab",""

返回值:

"-1"

dp 背包题

建立二维数组,记录字符到该位置的最大长度,例如字符串 s1 = SDSF 和 s2 = ASDF

SDSF
A0000
S1111
D1222
F1223

 数组建立逻辑

1、初始化第一行,将 A 与 s1 中逐一对比

2、初始化第一列,将 S 与 s2 逐一对比,结果val与 dp[yPos-1][xPos] 取最大值

3、每一个位置,如果字符相同,那这个点的值就是 dp[yPos-1][xPos-1] + 1。如果字符不相同,那这个点的值就是 Max(dp[yPos-1][xPos], dp[yPos][xPos-1])

4、从最后一行获取长度最大值,从该点开始搜索,每个点横向纵向把相同值全都走掉,记录最后点,然后 yPos--  xPos--,重复上述操作,直到边界。

SDSF
A0000
S1111
D1222
F1223

    public String LCS (String s1, String s2) {
        // write code here
        if (s1 == null || s2 == null || s1.isEmpty() || s2.isEmpty()) {
            return "-1";
        }
        int length1 = s1.length();
        int length2 = s2.length();
        if (length1 == 1 && s1.equals(s2)) {
            return s1;
        }
        int xPos;
        int yPos;
        int[][] dpMap = new int[length2][length1];
        int maxValue = 0;
        // 初始化数组
        for (xPos = 0; xPos < length1; xPos++) {
            char c = s2.charAt(0);
            if (c == s1.charAt(xPos)) {
                maxValue = 1;
            }
            dpMap[0][xPos] = maxValue;
        }
        maxValue = 0;
        for (yPos = 0; yPos < length2; yPos++) {
            char c = s1.charAt(0);
            if (c == s2.charAt(yPos)) {
                maxValue = 1;
            }
            dpMap[yPos][0] = maxValue;
        }
        // 背包字符串
        for (yPos = 1; yPos < length2; yPos++) {
            char c = s2.charAt(yPos);
            for (xPos = 1; xPos < length1; xPos++) {
                if (c == s1.charAt(xPos)) {
                    dpMap[yPos][xPos] = dpMap[yPos-1][xPos-1] + 1;
                } else {
                    dpMap[yPos][xPos] = Math.max(dpMap[yPos-1][xPos], dpMap[yPos][xPos-1]);
                }
            }
        }
        maxValue = -1;
        int maxPos = 0;
        // 找到最长串末尾
        for (xPos = 0; xPos < length1; xPos++) {
            if (maxValue < dpMap[length2-1][xPos]) {
                maxValue = dpMap[length2-1][xPos];
                maxPos = xPos;
            }
        }
        if (maxValue == 0) {
            return "-1";
        }
        xPos = maxPos;
        yPos = length2 - 1;
        char[] resultArray = new char[maxValue];
        maxValue--;
        while (xPos > 0 && yPos > 0 && maxValue >= 0) {
            if (dpMap[yPos-1][xPos] == dpMap[yPos][xPos]) {
                // 向上走到头
                for (; yPos > 0; yPos--) {
                    if (dpMap[yPos-1][xPos] != dpMap[yPos][xPos]) {
                        break;
                    }
                }
            }
            if (dpMap[yPos][xPos-1] == dpMap[yPos][xPos]) {
                // 向左走到头
                for(; xPos > 0; xPos--) {
                    if (dpMap[yPos][xPos-1] != dpMap[yPos][xPos]) {
                        break;
                    }
                }
            }
            resultArray[maxValue--] = s1.charAt(xPos);
            xPos--;
            yPos--;
        }
        if (maxValue == 0) {
            if (yPos > 0 && dpMap[yPos-1][xPos] == dpMap[yPos][xPos]) {
                // 向上走到头
                for (; yPos > 0; yPos--) {
                    if (dpMap[yPos-1][xPos] != dpMap[yPos][xPos]) {
                        break;
                    }
                }
            }
            if (xPos > 0 && dpMap[yPos][xPos-1] == dpMap[yPos][xPos]) {
                // 向左走到头
                for(; xPos > 0; xPos--) {
                    if (dpMap[yPos][xPos-1] != dpMap[yPos][xPos]) {
                        break;
                    }
                }
            }
            resultArray[0] = s1.charAt(xPos);
        }
        return new String(resultArray);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值