给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
在leetcode 1143 最长公共子序列中,dp[i][j]只是定义了在0-i,0-j这个范围内的最长公共子序列,不一定是一定要以i-1和j-1结尾。但是这里存在一个判断递增的问题,如果不以边界i结尾的话,如何判断呢?
定义dp[i]为以nums[i]结尾的最长递增子序列的长度(这个子序列一定是以nums[i]结尾),为了得到它的值,需要遍历j=[0,i-1], 将以 j 结尾的最长递增子序列 + nums[i]
- 如果nums[i] > nums[j] 则说明以 nums[j] 结尾的最长子序列如果加上 nums[i] 则仍然是递增序列,且长度又可以加1
- 否则不能形成递增序列
求上诉所有能形成递增序列的序列的最大长度,就是dp[i]
边界条件: 以任意一个i 位置结尾的递增子序列的极小值是1,因为一个字符本身形成一个递增子序列。因此dp所有位置初始为1
最终结果是遍历dp,求最大值,即遍历以各个位置为结尾的最长递增子序列,取他们的里面最大的那一个.
时间复杂度O(n2)
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
dp = [1]*len(nums)
gm = 1
for i in range(1, len(nums)):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[j] + 1, dp[i])
gm = max(dp[i], gm)
return gm
采用贪心+二分查找,时间复杂度能降低到O(nlogn)
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
dn = [nums[0]]
n = len(nums)
for i in range(1, n):
if nums[i] > dn[-1]:
dn.append(nums[i])
else:
loc = self.bisect_search(dn, nums[i])
dn[loc] = nums[i]
return len(dn)
def bisect_search(self, dn, target):
l, r = 0, len(dn)-1
while l <= r:
mid = (l+r) // 2
if dn[mid] >= target:
loc = mid
r = mid - 1
else:
l = mid + 1
return loc