最长递增子序列

回溯
回溯三问:
| Items | Description |
|---|---|
| 当前操作 | j∈[0, (n-1)]枚举 nums [j] |
| 子问题 | 数组前 i 个元素中最大的 LIS 长度 以 nums[i] 结尾的 LIS最大长度 |
| 子子问题 | 以 nums[j] 结尾的最大 LIS 长度 |
边界条件:i == 0时,返回1
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
n = len(nums)
@cache
def dfs(i):
if i==0:
return 1
ans = 1
for x in range (i):
if nums[x] < nums[i]:
ans = max(dfs(x)+1,ans)
return ans
ans = 1
for i in range(n):
ans = max(dfs(i),ans)
return ans
时间复杂度为O(n^2).使用记忆化搜索后,每个dfs(x)的计算时间为O(x).
递推
- f[i] 末尾为nums[i]的最大LIS长度
- 递推公式:
f[i] = max(f[j])+1 # j<i - 初始化:
f = [1]*n, - 便利顺序: 需要更新后的左边
f[j],顺序便利
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
n = len(nums)
f = [0]*n
for i in range(n):
ans = 1
for j in range(i):
if nums[j] < nums[i]:
ans = max(f[j]+1,ans)
f[i] = ans
return max(f)
时间复杂度为O(n^2).
二分&贪心
我们将问题反转:找到长度为某定值下,末尾元素中的最小值。最小的末尾元素,才能找到最长LIS。
Ex:nums = [1,6,8,2,5,6,3]
g[x]表示长度为x+1LIS,末尾元素的最小值
| 当前便利值 | 更新情况 |
|---|---|
| 1 | g[0] = 1; g = [1] |
| 6 | g[1] = 6; g = [1,6] |
| 8 | g[2] = 8; g = [1,6,8] |
| 2 | g[1] = 2; g = [1,2,8] |
| 5 | g[2] = 5; g = [1,2,5] |
| 6 | g[3] = 6; g = [1,2,5,6] |
| 3 | g[2] = 3; g = [1,2,3,6] |
最终可以看到,g 的长度就是结果。
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
g = []
for x in nums:
j = bisect_left(g,x)
if j==len(g):
g.append(x)
else :
g[j] =x
return len(g)
时间复杂度O(nlogn)
bisect_left(a, x, lo=0, hi=len(a))
返回 x 在有序列表 a 中的最左插入位置,使得插入后列表仍然有序。
如果 x 已经存在于 a 中,返回第一个等于 x 的索引。
如果 x 不存在,返回第一个大于 x 的元素的索引(即 x 应该插入的位置)。
1053

被折叠的 条评论
为什么被折叠?



