给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
【中等】
【分析】动态规划:状态+状态转移方程。
设dp[i]
为以num[i]
结尾的前面子串{num[0],...,num[i]}
的最长上升子串的长度。
dp[i]=1
dp[i]=max{dp[i],dp[j]+1} for j in range(i) if dp[i]>dp[j]
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums)==0:
return 0
dp=[1 for i in range(len(nums))]
for i in range(1,len(nums)):
for j in range(i):
if nums[i]>nums[j]:
dp[i]=max(dp[i],dp[j]+1)
return max(dp)
【分析】动态规划+二分查找
nums
中的值,用dp的下标表示其值在当前位置下的最长上升子串长度-1(为什么要-1,因为下标从0开始的)。
dp[-1] : nums[i]
直接加入dp的末尾;
dp
中利用二分查找,并且把dp[j]>=nums[i] and dp[j-1]的j这个位置的值替换成nums[i]
;
res
随dp
变化,取最长上升子串长度的最大值。nums=[1,3,6,7,9,4,10,5,6]
dp=[1],res=1
dp=[1,3],res=2
dp=[1,3,6],res=3
dp=[1,3,6,7],res=4
dp=[1,3,6,7,9],res=5
dp=[1,3,4,7,9],res=5
,当nums[i]=4,要把4 insert到dp中去,利用二分法找到应该insert的位置。dp=[1,3,4,7,9,10],res=6
dp=[1,3,4,5,9,10],res=6
dp=[1,3,4,5,6,10],res=6
注: # res既是当前i为止的最长升序子串的长度,也是dp中计入二分查找的升序数组的末尾下标。
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
dp=[0 for i in range(len(nums))]
res=0
for i in range(len(nums)):
l,r=0,res
while l>1
if dp[mid]>=nums[i]:
r=mid
else:
l=mid+1
dp[l]=nums[i]
res=max(res,l+1)
return res
注:进去while直接利用二分查找,巧妙十分啊!