1. 程式人生 > >【LeetCode 中等題】74-最長上升子序列

【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)