leetcode-动态规划【子序列问题】

目录

子序列(不连续)

300. 最长上升子序列

1143. 最长公共子序列

1035. 不相交的线

子序列(连续)

674. 最长连续递增序列

718. 最长重复子数组

53. 最大子序和

编辑距离

392. 判断子序列

115. 不同的子序列

583. 两个字符串的删除操作

72. 编辑距离

回文

647. 回文子串

516. 最长回文子序列


子序列(不连续)

300. 最长递增子序列

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 以nums[i]结尾最长上升子序列的长度
        dp = [0 for _ in range(len(nums))]
        dp[0] = 1
        for i in range(1, len(nums)):
            max_len = 0
            for j in range(i):
                if nums[j] < nums[i]:
                    cur_len = dp[j] + 1
                else:
                    cur_len = 1
                max_len = max(max_len, cur_len)
            dp[i] = max_len
        return max(dp)

1143. 最长公共子序列

class Solution(object):
    def longestCommonSubsequence(self, text1, text2):
        """
        :type text1: str
        :type text2: str
        :rtype: int
        """
        # dp[i][j]:text1[0:i]与text2[0:j]最长子序列长度
        dp = [[0 for _ in range(len(text2))] for _ in range(len(text1))]
        for i in range(len(text1)):
            for j in range(len(text2)):
                if i == 0 and j == 0 and text1[0] == text2[0]:
                    dp[0][0] = 1
                if i == 0:
                    if dp[0][j-1] or text1[0] == text2[j]:
                        dp[0][j] = 1
                    continue
                if j == 0:
                    if dp[i-1][0] or text1[i] == text2[0]:
                        dp[i][0] = 1
                    continue
                if text1[i] == text2[j]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
        return dp[-1][-1]

1035. 不相交的线

 本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!和上一题的思路是一样的。

子序列(连续)

674. 最长连续递增序列

class Solution(object):
    def findLengthOfLCIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 以nums[i]为结尾的数组连续递增子序列长度为dp[i]
        dp = [0 for _ in range(len(nums))]
        dp[0] = 1
        for i in range(1, len(nums)):
            if nums[i] > nums[i-1]:
                dp[i] = dp[i-1] + 1
            else:
                dp[i] = 1
        return max(dp)

718. 最长重复子数组

class Solution(object):
    def findLength(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: int
        """
        # dp[i][j]:以nums1[i]和nums2[j]结尾的两个子序列最长重复子数组长度
        dp = [[0 for _ in range(len(nums2))] for _ in range(len(nums1))]
        ans = 0
        for i in range(len(nums1)):
            for j in range(len(nums2)):
                if nums1[i] != nums2[j]: dp[i][j] = 0
                else:
                    if i == 0 or j == 0: dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i-1][j-1] + 1
                ans = max(ans, dp[i][j])
        return ans

53. 最大子序和

# 巧妙的解法
class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        result = -float('inf')
        ans = 0
        for i in range(len(nums)):
            ans += nums[i]
            if ans > result: result = ans
            if ans <= 0: ans = 0
        return result
class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # dp[i]:以nums[i]为结尾的最大连续子数组和
        dp = [nums[0]]
        for i in range(1, len(nums)):
            dp.append(max(dp[i-1]+nums[i], nums[i]))
        return max(dp)

编辑距离

392. 判断子序列

# dp[i][j]:s[:j]是否为t[:i]的子序列 0/1
class Solution(object):
    def isSubsequence(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        if len(s) == 0: return True
        if len(s) > len(t): return False
        # dp[i][j]:s[:j]是否为t[:i]的子序列 0/1
        dp = [[0 for _ in range(len(s))] for _ in range(len(t))]
        for i in range(len(t)):
            for j in range(len(s)):
                if i == 0 and j == 0:
                    if s[0] == t[0]: dp[i][j] = 1
                elif i == 0:
                    continue
                elif i < j:
                    continue
                else:
                    if t[i] == s[j]:
                        if j > 0: dp[i][j] = dp[i-1][j-1]
                        else: dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i-1][j]
        return dp[-1][-1] == 1
# dp[i][j]:t[:i]和s[:j]的公共子序列长度
class Solution(object):
    def isSubsequence(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        if len(s) == 0: return True
        if len(t) < len(s): return False
        # dp[i][j]:t[:i]和s[:j]的公共子序列长度
        dp = [[0 for _ in range(len(s))] for _ in range(len(t))]
        for i in range(len(t)):
            for j in range(len(s)):
                if t[i] == s[j]:
                    if i == 0 or j == 0: dp[i][j] = 1
                    else: dp[i][j] = dp[i-1][j-1] + 1
                else:
                    if i == 0 and j == 0: dp[i][j] = 0
                    elif i == 0: dp[i][j] = dp[i][j-1]
                    elif j == 0: dp[i][j] = dp[i-1][j]
                    else: dp[i][j] = max(dp[i][j-1], dp[i-1][j])
        return dp[-1][-1] == len(s)

115. 不同的子序列

class Solution(object):
    def numDistinct(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: int
        """
        # dp[i][j]:s[:i]中存在t[:j]的个数
        dp = [[0 for _ in range(len(t)+1)] for _ in range(len(s)+1)]
        # 当t为空序列时设置s包含一个t
        for i in range(len(s)+1):
            dp[i][0] = 1
        for i in range(1, len(s)+1):
            for j in range(1, len(t)+1):
                if s[i-1] == t[j-1]:
                    dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
                else:
                    dp[i][j] = dp[i-1][j]
        return dp[-1][-1]

583. 两个字符串的删除操作

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        # dp[i][j]:在word1[:i]和word2[:j]中最长公共子序列长度
        dp = [[0 for _ in range(len(word2)+1)] for _ in range(len(word1)+1)]
        for i in range(1, len(word1)+1):
            for j in range(1, len(word2)+1):
                if word1[i-1] == word2[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
        max_len = dp[-1][-1]
        return len(word1) + len(word2) - 2*max_len
class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        # dp[i][j]:word1[:i]和word2[:j]变成一样的序列所需要的操作数
        dp = [[0 for _ in range(len(word2)+1)] for _ in range(len(word1)+1)]
        for i in range(len(word1)+1):
            dp[i][0] = i
        for j in range(len(word2)+1):
            dp[0][j] = j
        for i in range(1, len(word1)+1):
            for j in range(1, len(word2)+1):
                if word1[i-1] == word2[j-1]:
                    dp[i][j] = dp[i-1][j-1]
                else:
                    dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+2)
        return dp[-1][-1]

72. 编辑距离

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        # dp[i][j]:word1[:i]和word2[:j]变成一样的序列所需要的操作数
        dp = [[0 for _ in range(len(word2)+1)] for _ in range(len(word1)+1)]
        for i in range(len(word1)+1):
            dp[i][0] = i
        for j in range(len(word2)+1):
            dp[0][j] = j
        for i in range(1, len(word1)+1):
            for j in range(1, len(word2)+1):
                if word1[i-1] == word2[j-1]:
                    dp[i][j] = dp[i-1][j-1]
                else:
                    # 1. 插入:word1删除相当于word2插入,word2删除相当于word1插入
                    # 2. 删除:
                    # 2.1 word1删除:dp[i][j] = dp[i-1][j]+1
                    # 2.2 word2删除:dp[i][j] = dp[i][j-1]+1
                    # 3. 替换:dp[i][j] = dp[i-1][j-1]+1
                    dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+1)
        return dp[-1][-1]

回文

647. 回文子串

class Solution(object):
    def countSubstrings(self, s):
        """
        :type s: str
        :rtype: int
        """
        count = 0
        # dp[i][j]:s[i:j]内的子串是否为回文子串
        dp = [[0 for _ in range(len(s))] for _ in range(len(s))]
        # 从左下角开始遍历
        for i in range(len(s)-1, -1, -1):
            for j in range(i, len(s)):
                if s[i] == s[j]:
                    if j-i <= 1:
                        dp[i][j] = 1
                        count += 1
                    else:
                        if dp[i+1][j-1]:
                            dp[i][j] = 1
                            count += 1
        return count

516. 最长回文子序列

class Solution(object):
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        # dp[i][j]:s[i:j]内的最长回文子串长度
        dp = [[0 for _ in range(len(s))] for _ in range(len(s))]
        for i in range(len(s)):
            dp[i][i] = 1
        # 从左下角开始遍历
        for i in range(len(s)-1, -1, -1):
            for j in range(i, len(s)):
                if s[i] == s[j]:
                    if j-i <= 1: dp[i][j] = j-i+1
                    else: dp[i][j] = dp[i+1][j-1]+2
                else:
                    dp[i][j] = max(dp[i][j-1], dp[i+1][j])
        return dp[0][-1]
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值