Leetcode 1143.最长公共子序列(求长度)

Time: 20190906
Type: Medium

题目描述

给定两个字符串text1text2,返回它们的最长公共子序列。

子序列是通过原字符串删除一些字符(可以不删)生成的新的字符串,不改变原来字符的相对顺序。比如aceabcde的子序列,而aec则不是。

公共子序列是指该序列是两个字符串都有的子序列。

如果没有公共子序列,则返回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.

思路

本题是动态规划经典题型了。

两个字符串,因此可以想到用二维DP来表达状态。

f[i][j]表示text1中到i下标为止的字符和text2中到j为止的下标的字符的最长公共子序列长度。

f[i][j]的求解可以向左查看三个状态:

  • f[i-1][j-1]
  • f[i][j-1]
  • f[i-1][j]

如果当前字符相等,则:f[i][j] = f[i-1][j-1] + 1,否则:f[i][j] = max(f[i-1][j], f[i][j-1])

代码

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        
        m = len(text1)
        n = len(text2)
        if m < 1 or n < 1:
            return 0
        
        f = [[0] * (n + 1) for _ in range(m + 1) ]
        # f[i][j]表示text1中[1...i], text2中[1...j]LCS的长度
        # f[i][j] = f[i-1][j-1] if text1[i-1] != text2[j-1] else max(f[i-1][j], f[i][j-1])
        res = ""
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if text1[i-1] == text2[j-1]:
                	res += text1[i-1] # 
                    f[i][j] = f[i-1][j-1] + 1
                else:
                    f[i][j] = max(f[i-1][j], f[i][j-1])
        print(res) # 即为最长公共子序列
        return f[m][n]

本题有个小技巧是从i=1j=1开始使用,如果从0开始就比较难处理f[1][0]和f[0][1]两种状态。因为从0开始,f[1][0]表示text1提供两个字符,text2提供1个字符,需要向左再开拓一个状态表示一个提供1个字符,一个不提供字符的情况。

求出最大长度 + 打印出LCS

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        
        m = len(text1)
        n = len(text2)
        if m < 1 or n < 1:
            return 0
        
        f = [[0] * (n + 1) for _ in range(m + 1) ]
        # f[i][j]表示text1中[1...i], text2中[1...j]LCS的长度
        # f[i][j] = f[i-1][j-1] if text1[i-1] != text2[j-1] else max(f[i-1][j], f[i][j-1])
        
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if text1[i-1] == text2[j-1]:
                    f[i][j] = f[i-1][j-1] + 1
                else:
                    f[i][j] = max(f[i-1][j], f[i][j-1])
        
        # Following code is used to print LCS 
        index = f[m][n] 

        # Create a character array to store the lcs string 
        lcs = [""] * (index + 1) 
        lcs[index] = "" 

        # Start from the right-most-bottom-most corner and 
        # one by one store characters in lcs[] 
        i = m 
        j = n 
        while i > 0 and j > 0: 

            # If current character in X[] and Y are same, then 
            # current character is part of LCS 
            if text1[i-1] == text2[j-1]: 
                lcs[index-1] = text1[i-1] 
                i -= 1
                j -= 1
                index -= 1

            # If not same, then find the larger of two and 
            # go in the direction of larger value 
            elif f[i-1][j] > f[i][j-1]: 
                i -= 1
            else: 
                j -= 1

        print("lcs is: ", lcs) # lcs是数组形式
  
        return f[m][n]

相似题型

Leetcode 72.编辑距离
Leetcode 10.正则表达式匹配
Leetcode 44.通配符匹配

END.

你可能感兴趣的:(LeetCode)