给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
LeetCode 链接
0~i
,最终状态为序列 0~n-1
,n
为序列的长度,则用 dp[i]
记录当前位置 i
处的最长上升子序列的长度。dp[i]
,若 nums[i]>nums[j]
,0<=j,则判断 dp[j]+1
大于 dp[i]
,若是则更新 dp[i]
。因此有 i-1
种选择,需要通过两次遍历求解,时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
class Solution:
def lengthOfLIS(self, nums):
if not nums:
return 0
n, res = len(nums), 1 # 序列长度和初始化最长上升子序列长度
dp = [1]*n # 初始化 dp
for i in range(1, n):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j]+1) # 更新 dp
res = max(res, dp[i]) # 更新最长上升子序列长度
return res
test = Solution()
nums = [10,9,2,5,3,7,101,18]
test.lengthOfLIS(nums)
4
0~n-1
的值插入到数组的尾端,数组要求从大到小排序,若无法插入,则添加一个包含该值的新数组;遍历结束后,数组的个数即为最长上升子序列的长度class Solution:
def lengthOfLIS(self, nums):
if not nums:
return 0
top = [] # 整体数组
for i in range(len(nums)):
# 二分查找插入数组
left, right = 0, len(top)-1 # 左右边界索引
while left <= right:
mid = (left+right)//2 # 左中位数
if top[mid][-1] < nums[i]:
left = mid+1
else:
right = mid-1
# 若 left 等于数组的个数,则需要添加新数组;否则,在 left 数组尾部添加新值
if left == len(top):
top.append([nums[i]])
else:
top[left].append(nums[i])
return len(top)
test = Solution()
nums = [10,9,2,5,3,7,101,18]
test.lengthOfLIS(nums)
4
class Solution:
def lengthOfLIS(self, nums):
if not nums:
return 0
top = []
for i in range(len(nums)):
# 二分查找
left, right = 0, len(top)-1 # 左右边界索引
while left <= right:
mid = (left+right)//2 # 左中位数
if top[mid] < nums[i]:
left = mid+1
else:
right = mid-1
# 若 left 等于数组长度,则需要添加新值;否则,在 left 位置的值覆盖为新值
if left == len(top):
top.append(nums[i])
else:
top[left] = nums[i]
return len(top)
test = Solution()
nums = [10,9,2,5,3,7,101,18]
test.lengthOfLIS(nums)
4
LeetCode 题解