【LeetCode 中等题】74-最长上升子序列

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

示例:

输入:
[10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:

  • 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
  • 你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

解法1。O(n^2),这里是子序列,不是子串,说明不必连着,用memo[i]记录以nums[i]结尾的子序列最长长度,所以只需要比较截至nums[i],遍历在这之前的元素有多少升序。

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

解法2。O(nlogn),DP解法。思路是,我们先建立一个数组ends,把首元素放进去,然后比较之后的元素,如果遍历到的新元素比ends数组中的首元素小的话,替换首元素为此新元素,如果遍历到的新元素比ends数组中的末尾元素还大的话,将此新元素添加到ends数组末尾(注意不覆盖原末尾元素)。如果遍历到的新元素比ends数组首元素大,比尾元素小时,此时用二分查找法找到第一个不小于此新元素的位置,覆盖掉位置的原来的数字,以此类推直至遍历完整个nums数组,此时ends数组的长度就是我们要求的LIS的长度,特别注意的是ends数组的值可能不是一个真实的LIS,比如若输入数组nums为{4, 2, 4, 5, 3, 7},那么算完后的ends数组为{2, 3, 5, 7},可以发现它不是一个原数组的LIS,只是长度相等而已,千万要注意这点。

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        ends = [nums[0]]
        for n in nums:
            if n < ends[0]:
                ends[0] = n
            elif n> ends[-1]:
                ends.append(n)
            else:
                left = 0
                right = len(ends)
                while left < right:
                    mid = (left+right)//2
                    if ends[mid] < n:
                        left = mid+1
                    else:
                        right = mid
                ends[right] = n
        return len(ends)

猜你喜欢

转载自blog.csdn.net/weixin_41011942/article/details/86422830