1143. Longest-Common-Subsequence

difficulty: Medium

Given two strings text1 and text2, return the length of their longest common subsequence.

A subsequence of a string is a new string generated from the original string with some characters(can be none) deleted without changing the relative order of the remaining characters. (eg, "ace" is a subsequence of "abcde" while "aec" is not). A common subsequence of two strings is a subsequence that is common to both strings.

If there is no common subsequence, return 0.

Example 1:

Input: text1 = "abcde", text2 = "ace" 
Output: 3  
Explanation: The longest common subsequence is "ace" and its length is 3.

Example 2:

Input: text1 = "abc", text2 = "abc"
Output: 3
Explanation: The longest common subsequence is "abc" and its length is 3.

Example 3:

Input: text1 = "abc", text2 = "def"
Output: 0
Explanation: There is no such common subsequence, so the result is 0.

Constraints:

  • 1 <= text1.length <= 1000

  • 1 <= text2.length <= 1000

  • The input strings consist of lowercase English characters only.

Method One

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        // 这个题得好好看看
        // 首先搞明白题意,这是 subsequence 不是 substring. 
        // 比如 abc 和 adc 的 longest common subsequence 是 ac. 即,只要在string中的相对顺序不变就行。
        // 这个办法是建一个 2D dp 数组,代表啥呢?
    //   index 0 1 2 3
    //   index / a b c 
        // 0 / 0 0 0 0    
        // 1 a 0 1 1 1
        // 2 d 0 1 1 1
        // 3 c 0 1 1 2
        // 比如 (1,1) 是 1, a 和 a 相等,最长子数组是 1.
        // (1, 2)  位置,是 1,代表着是 ab 和 a 的最长子数组, 由于 b /= a, 所以我们保持之前的最长记录。
        // 我们到了 (1,3) 位置是 abc 和 a, c /= a, 同样保持之前的最长纪录。
        // 而 (2,2) 位置是 ab 和 ad 的最长子数组。
        // (3,3) 是 abc 和 adc 有 c == c, 那么我们就在 ab 和 ad 的记录上面再增加 1. 
        // 可以看这个 一看就明白 https://www.youtube.com/watch?v=Dumq-rceuac
        // 但是他解释的很差
        int m = text1.length();
        int n = text2.length();
        int[][] dp = new int[ m + 1][ n + 1];
        for(int i = 0; i < m; i++ ) {
            for( int j = 0; j < n; j++ ) {
                if( text1.charAt(i) == text2.charAt(j) ) {
                    dp[i + 1][j + 1] = dp[i][j] + 1;
                }else{
                    dp[i + 1][j + 1] = Math.max(dp[i][j + 1],dp[i + 1][j] );
                }
            }
        }    
        return dp[m][n];
    }
}

需要补充一些分析: 这个题当然是要用动态规划的。 问题是如果给你了子问题的答案,你怎么处理呢? 比如两个 String, 用 strA, strB 来表示,strA1, strB1 代表 strA 和 strB 去掉最后一个字母的 String。 其实如何自然的得出这个分类,我也没想好,还是直接跳跃的来解释吧! 现在知道的子问题的结果是: strA1, strB : l1, strA, strB1 : l2, strA1, strB1: l3, 对于以上每种情况,为了推导到 strA, strB 的答案, 我们都需要做一个运算, 就是对比 strA, strB 最后一个字母是否相同。 第一种情况,这两个字母如果不相同,很明显,我们取 l1, l2, l3 的最大值即可,但是显然 l1, l2 >= l3, 而且 l1, l2 最多比 l3 大 1, 即 l3 + 1 >= l1, l2 >= l3 . 因此这种情况,我们只比较 l1, l2. 另一种情况是 strA, strB 的最后一个字母相同。 那么我们要的结果至少是 l3 + 1。至于 l1, l2, 其实我们没法说。但是由于 l3 + 1 >= l1, l2 >= l3. 所以我们直接取 l3 + 1 就好了。

Last updated

Was this helpful?