题目描述:给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入:[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)