Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

最长公共子序列-1143 #85

Open
sl1673495 opened this issue Jun 17, 2020 · 0 comments
Open

最长公共子序列-1143 #85

sl1673495 opened this issue Jun 17, 2020 · 0 comments
Labels
动态规划 待复习 看题解或者做出来很艰难的,需要回顾。

Comments

@sl1673495
Copy link
Owner

sl1673495 commented Jun 17, 2020

给定两个字符串  text1 和  text2,返回这两个字符串的最长公共子序列的长度。

一个字符串的子序列是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

若这两个字符串没有公共子序列,则返回 0。

示例 1:

输入:text1 = "abcde", text2 = "ace"
输出:3
解释:最长公共子序列是 "ace",它的长度为 3。
示例 2:

输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc",它的长度为 3。
示例 3:

输入:text1 = "abc", text2 = "def"
输出:0
解释:两个字符串没有公共子序列,返回 0。
 

提示:

1 <= text1.length <= 1000
1 <= text2.length <= 1000
输入的字符串只含有小写英文字符。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-common-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

把两个字符长度都置为 1 开始规划基础状态,注意这是一个二维的 dp 数组, dp[m][n] 中的 m 和 n 分别代表字符串 1 的长度和字符串 2 的长度,这个坐标的状态就是「字符串 1 长度为 m 且字符串 2 长度为 n 时的最长公共序列长度」。

对于 dp[m][n] 来说,分为两种情况:

  1. s1[m] === s2[n] 字符相等,那么就直接等于 1 + dp[m - 1][n - 1],也就是当前相等所得到的长度 1 加上两个字符各减去一位后的最长子序列长度。

  2. s1[m] !== s2[n] 字符不相等,那么就分别尝试把两边各减去一位,求它们的最长子序列长度中的 最大值,也就是 max(dp[m][n - 1], dp[m - 1][n])

image

理清楚这个关系后,就可以开始写传统的二维数组 dp 求解了,动态规划是自底向上的,所以我们从字符位置都在 0 的情况开始,慢慢的向上求解。

注意这题里要提前把溢出情况比如 dp[-1][0]dp[-1][-1] 提前设置为 0,防止访问时报错。比如在求解 dp[0][0] 并且两个字符串的第 0 位都相同的时候就会转而去求 dp[-1][-1]

/**
 * @param {string} text1
 * @param {string} text2
 * @return {number}
 */
let longestCommonSubsequence = function (text1, text2) {
    let n1 = text1.length
    let n2 = text2.length

    let dp = []

    for (let i1 = 0; i1 <= n1; i1++) {
        dp[i1] = []
        dp[i1][0] = 0
    }
    dp[0] = Array(n2 + 1).fill(0)

    for (let i1 = 1; i1 <= n1; i1++) {
        for (let i2 = 1; i2 <= n2; i2++) {
            let str1 = text1[i1 - 1]
            let str2 = text2[i2 - 1]

            if (str1 === str2) {
                dp[i1][i2] = 1 + dp[i1 - 1][i2 - 1]
            }else {
                dp[i1][i2] = Math.max(dp[i1 - 1][i2], dp[i1][i2 - 1])
            }
        }
    }

    return dp[n1][n2]
};
@sl1673495 sl1673495 added 动态规划 待复习 看题解或者做出来很艰难的,需要回顾。 labels Jun 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
动态规划 待复习 看题解或者做出来很艰难的,需要回顾。
Projects
None yet
Development

No branches or pull requests

1 participant