【LeetCode 中等題】74-最長上升子序列
阿新 • • 發佈:2019-01-14
題目描述:給定一個無序的整數陣列,找到其中最長上升子序列的長度。
示例:
輸入:[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)