LeetCode 300. 最长递增子序列 / 673. 最长递增子序列【个数】(Medium)/ 子数组、序列问题!!!

300. 最长递增子序列

在这里插入图片描述
【题目链接】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution:
    ### 1215 动态规划(3656 ms,15 MB)
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums: return 0

        # 初始化dp,1表示每个数字都以自身为最小的有序子数组
        dp = [1] * len(nums)

        # 遍历原数组nums中的每一个数num
        for i in range(len(nums)):
            # 遍历在num之前的每一个数
            for j in range(i):
                # 若当前两个数是有序关系,则更新dp[i];否则表示有序关系中断,则已有的值会更大,此时无需更新
                if nums[i] > nums[j]: dp[i] = max(dp[i], dp[j]+1)
        
        return max(dp) # 最后返回dp的最大值

    
    ### 1215 动态规划 + 二分法(68 ms,15 MB)
    def lengthOfLIS(self, nums: List[int]) -> int:
        # 初始化单调递增(子)数组dp,即dp的有效长度dp_len
        # dp[i]表示长度为i+1的子序列的最后一个元素的值,dp是单调递增的
        dp, dp_len = [0] * len(nums), 0

        # 遍历原数组nums中的每一个数num
        for num in nums:
            i, j = 0, dp_len

            # 二分查找,为当前num寻找到dp中合适的位置
            # 检查dp[0:dp_len]中是否存在比num大的值,若存在则将num插入对应的位置
            # 保证整个dp是递增的
            while i < j:
                m = (i + j) // 2
                # 未找到大于num的数时,i前移;否则j前移(<表示严格单调,<=表示非严格单调)
                if dp[m] < num: i = m + 1
                else: j = m

            # 更新dp[i]
            dp[i] = num

            # 若当前值num大于dp中的最后一个值(即dp的最大值,此时下标j未改变)
            # 则dp的有效长度dp_len加一(即表示num加入后可以构成更长的有序子数组)
            if j == dp_len: dp_len += 1

        return dp_len
  • 返回最长递增子序列
def LIS(nums):
    if len(nums) == 0: return []
    if len(nums) == 1: return nums
    
    n = len(nums)
    # a[i]表示以下标为i的元素作为结尾的最长递增子序列的长度
    a = [0] * n
    # dp[i]表示长度为i+1的子序列的最后一个元素的值,dp是单调递增的
    dp = [0] * n 
    dp_len = 0 # 最长递增子序列的长度,从0开始增加到最后的值
    
    for i in range(n):
        # 二分查找,为当前num寻找到dp中合适的位置
        # 检查dp[0:dp_len]中是否存在比nums[i]大的值,若存在则将nums[i]插入对应的位置
        # 保证整个dp是递增的
        l, r = 0, dp_len
        while l < r:
            mid = (l + r) // 2
            if dp[mid] < nums[i]:
                l = mid + 1
            else:
                r = mid
        
        # 每过一个数nums[i],则把它作为长度为l+1的子序列的最后一个元素,是一种更新操作
        dp[l] = nums[i]
        
        # 若当前值num大于dp中的最后一个值(即dp的最大值,此时下标j未改变)
        # 则dp的有效长度dp_len加一(即表示num加入后可以构成更长的有序子数组)
        if r == dp_len: dp_len += 1
            
        a[i] = r + 1 # 每过一个数都能确定以该数结尾的最长递增子序列的长度
    
    # 根据dp_len的长度递减,来从后往前寻找最长递增子序列中的每一个数
    res = [0] * dp_len
    for i in range(n - 1, -1, -1):
        # 若当前的dp_len恰好为a中的某一个值,则寻找到其中的一个数
        if dp_len == a[i]:
            # 根据dp_len作为下标,把元素放入对应的位置,然后dp_len长度减一
            res[dp_len - 1] = nums[i]
            dp_len -= 1
    
    return res

在这里插入图片描述

673. 最长递增子序列个数

在这里插入图片描述

class Solution(object):
    def findNumberOfLIS(self, nums):
        n = len(nums)
        if n <= 1: return n

        dp = [0] * n     # dp[i]表示以nums[i]结尾的最长递增子序列的长度
        counts = [1] * n # counts[i]表示以nums[i]结尾的最长递增子序列的个数

        for j, num in enumerate(nums):
            for i in range(j):
                if nums[i] < nums[j]:  # 若当前数i < 固定数j,才表明出现更长的子序列
                    if dp[i] >= dp[j]: # 若是初始化的值,则最长子序列的长度直接在dp[i]的基础上加一
                        dp[j] = dp[i] + 1
                        counts[j] = counts[i] # 若是初始化的值,则最长子序列的个数与counts[i]相同
                    elif dp[i] + 1 == dp[j]:  # 若j之前某一个值i能与j构成递增子序列,则j处的最长子序列的个数会累加上i处的个数
                        counts[j] += counts[i]

        longest = max(dp)
        return sum(c for i, c in enumerate(counts) if dp[i] == longest) # 统计不同的最长的递增子序列的总个数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值