最长递增子序列【基础算法精讲 20】_哔哩哔哩_bilibili
300. 最长递增子序列
给你一个整数数组 nums
,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的子序列。
方法一:动态规划之「枚举选哪个」
写法一:记忆化搜索
dfs(i) 表示以 nums[i] 结尾的 LIS 的长度。
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
@cache
def dfs(i: int) -> int:
res = 0
for j in range(i):
if nums[j] < nums[i]:
res = max(res, dfs(j))
return res + 1
return max(dfs(i) for i in range(len(nums)))
写法二:一比一翻译成递推
把 dfs 改成 f 数组,递归改成循环,就完事了。
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
f = [0] * len(nums)
for i, x in enumerate(nums):
for j, y in enumerate(nums[:i]):
if x > y:
f[i] = max(f[i], f[j])
f[i] += 1
return max(f)
方法二:贪心 + 二分查找
前置知识:二分查找
写法一:额外空间
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
g = []
for x in nums:
j = bisect_left(g, x)
if j == len(g): # >=x 的 g[j] 不存在
g.append(x)
else:
g[j] = x
return len(g)
写法二:原地修改
直接把 g 填入 nums中。
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
ng = 0 # g 的长度
for x in nums:
j = bisect_left(nums, x, 0, ng)
nums[j] = x
if j == ng: # >=x 的 g[j] 不存在
ng += 1
return ng
1626. 无矛盾的最佳球队
假设你是球队的经理。对于即将到来的锦标赛,你想组合一支总体得分最高的球队。球队的得分是球队中所有球员的分数 总和 。
然而,球队中的矛盾会限制球员的发挥,所以必须选出一支 没有矛盾 的球队。如果一名年龄较小球员的分数 严格大于 一名年龄较大的球员,则存在矛盾。同龄球员之间不会发生矛盾。
给你两个列表 scores
和 ages
,其中每组 scores[i]
和 ages[i]
表示第 i
名球员的分数和年龄。请你返回 所有可能的无矛盾球队中得分最高那支的分数 。
方法一:排序 + 动态规划
前置知识:动态规划
class Solution:
def bestTeamScore(self, scores: List[int], ages: List[int]) -> int:
a = sorted(zip(scores, ages))
f = [0] * len(a)
for i, (score, age) in enumerate(a):
for j in range(i):
if a[j][1] <= age:
f[i] = max(f[i], f[j])
f[i] += score
return max(f)
方法二:基于值域计算
class Solution:
def bestTeamScore(self, scores: List[int], ages: List[int]) -> int:
max_sum = [0] * (max(ages) + 1)
for score, age in sorted(zip(scores, ages)):
max_sum[age] = max(max_sum[:age + 1]) + score
return max(max_sum)
方法三:树状数组优化
前置知识:树状数组
class Solution:
def bestTeamScore(self, scores: List[int], ages: List[int]) -> int:
u = max(ages)
t = [0] * (u + 1)
# 返回 max(max_sum[:i+1])
def query(i: int) -> int:
mx = 0
while i:
mx = max(mx, t[i])
i &= i - 1
return mx
# 更新 max_sum[i] 为 mx
def update(i: int, mx: int) -> None:
while i < len(t):
t[i] = max(t[i], mx)
i += i & -i
for score, age in sorted(zip(scores, ages)):
update(age, query(age) + score)
return query(u)