sl1673495 / leetcode-javascript

:beers: 喝杯小酒,一起做题。前端攻城狮从零入门算法的宝藏题库,根据知名算法老师的经验总结了 100+ 道 LeetCode 力扣的经典题型 JavaScript 题解和思路。已按题目类型分 label,一起加油。

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

最长公共子序列-1143

sl1673495 opened this issue · comments

commented

给定两个字符串  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]
};