DP、二分-LeetCode300. 最长上升子序列LIS+673. 最长递增子序列的个数(Python)

1、题目描述

https://leetcode-cn.com/problems/longest-increasing-subsequence/

给定一个无序的整数数组,找到其中最长上升子序列的长度。

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。

相关题:673. 最长递增子序列的个数(有几组最长递增子序列)

2、代码详解(拓:打印出这个LIS)

法一:DP,O(N^2),掌握

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums: return 0
        dp = [1] * len(nums)
        for i in range(len(nums)):
            for j in range(i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j] + 1)
        return max(dp)

nums = [10, 9, 2, 5, 3, 7, 101, 18]
s = Solution()
print(s.lengthOfLIS(nums))

打印出这个序列

  • 开一个pi决策数组,记录从哪一个状态转移过来的(记录上一个状态的下标)
  • 记录结束标志pEnd
  • 从结束标志开始,反向找前一个状态
class Solution(object):
    def lengthOfLIS(self, nums):
        if not nums: return 0

        n = len(nums)
        # dp[i] 表示以nums[i]为结尾的最长上升子序列的长度
        dp = [1] * n

        pi = [-1] * n  # 决策数组,记录前一次选的哪一个
        pEnd = 0  # 结束标志
        res = 0

        for i in range(n):
            for j in range(i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j] + 1)

                    if dp[j] + 1 == dp[i]:  # 产生更新
                        pi[i] = j  # 决策数组记录, 从j转移过来

            res = max(res, dp[i])  # res记录最大值

            if dp[i] == res:  # 如果是当前最大,记录一下结束标志pEnd
                pEnd = i

        seq = [-1] * res  # 打印序列数组

        for i in range(res-1, -1, -1):  # 反向找前一个状态
            seq[i] = nums[pEnd]
            pEnd = pi[pEnd]  # 更新为前一个

        print(pi)
        print(seq)

        return res

nums = [10, 9, 2, 5, 3, 7, 101, 18]
nums2 = [4, 2, 4, 5, 3, 7]
s = Solution()
print(s.lengthOfLIS(nums))
print(s.lengthOfLIS(nums2))

输出结果

[10, 9, 2, 5, 3, 7, 101, 18]  # 原始
[-1, -1, -1, 2, 2, 4, 5, 5]  # pi决策数组
[2, 3, 7, 18]  # 所求LIS
4  # 长度
[4, 2, 4, 5, 3, 7]  # 原始
[-1, -1, 1, 2, 1, 3]  # pi决策数组
[2, 4, 5, 7]  # LIS
4  # 长度

 

法二:二分查找,O(NlogN),了解

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        tails = [0] * len(nums)
        size = 0
        for x in nums:
            i, j = 0, size
            while i != j:
                m = (i + j) / 2
                if tails[m] < x:
                    i = m + 1
                else:
                    j = m
            tails[i] = x
            size = max(i + 1, size)
        return size

代码链接:

https://leetcode.com/problems/longest-increasing-subsequence/discuss/74824/JavaPython-Binary-search-O(nlogn)-time-with-explanation

思路链接:纸牌游戏(耐心排序)

https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-she-ji-fang-fa-zhi-pai-you-xi-jia/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值