【动态规划】最长递增子序列
最长递增子序列
简介
最长递增子序列(Longest Increasing Subsequence)是指找到一个给定序列的最长子序列的长度,使得子序列中的所有元素单调递增。
例如,
分析
方法一: 转换为LCS
我们可以把 求最长递增子序列问题 转化为求 最长公共子序列 的问题。
例如,
数组
参考:最长公共子序列
方法二:动态规划
设数组
初始条件
每一个字符都是长度为
状态转移方程
每一个较大的元素结尾的子序列,都可以由以它前一个小于它的元素结尾的子序列转移而来。
这里,我们直接给出状态转移方程,当
例如,
代码实现
from typing import List class Solution: @staticmethod def lengthOfLIS(nums: List[int]) -> int: n = len(nums) dp = [1] * n for i in range(1, n): for j in range(i): if nums[i] > nums[j]: dp[i] = max(dp[j] + 1, dp[i]) return max(dp)
方法三:二分法
设
也就是说,我们要保证
例如,假设
- 当
时,所有的递增子序列: , , , ,此时 ; - 当
时, 所有的递增子序列: , , ,此时 ; - 当
时, 所有的递增子序列: ,此时 ; - 当
时,不存在递增子序列。
容易看出,
- 要么,它能找到一个位置,并 替换 掉已有元素;
- 或者,它大于当前
中所有的元素,这时将其 追加 已有元素的最后。
遍历完数组后,最终,
例如,以
- 当
时,在 的位置 插入元素 , ; - 当
时,在 的位置 插入元素 , ; - 当
时,在 的位置 覆盖元素 , ; - 当
时,在 的位置 插入元素 , ; - 当
时,在 的位置 覆盖元素 , ; - 当
时,在 的位置 追加元素 , ;
最终,
代码实现
from typing import List class Solution: @staticmethod def lengthOfLIS(nums: List[int]) -> int: """ 求最长递增子序列 """ tails = [0] * len(nums) size = 0 for num in nums: left, right = 0, size # 通过二分法,为num在tail数组中一个插入位置 while left != right: mid = (left + right) // 2 if tails[mid] < num: left = mid + 1 else: right = mid tails[left] = num # 记录tail数组中不为零的元素的长度 if left == size: size += 1 return size
应用
应用1:Leetcode.300
题目
分析
参考前面的算法分析。
代码实现
class Solution: def lengthOfLIS(self, nums: List[int]) -> int: n = len(nums) dp = [1] * n for i in range(1, n): for j in range(i): if nums[i] > nums[j]: dp[i] = max(dp[j] + 1, dp[i]) return dp[n - 1]
应用2:Leetcode.354
题目
分析
由于能嵌套的信封的长和宽必须严格递减,所以我们将原有的信封尺寸,先按照
然后,再取排序后的
代码实现
from typing import List class Solution: def maxEnvelopes(self, envelopes: List[List[int]]) -> int: # 基于w升序,h降序排序 envelopes = sorted(envelopes, key=lambda x: (x[0], -x[1])) # 寻找以h升序的最长子序列 heights = [envelope[1] for envelope in envelopes] return self.lengthOfLIS(heights) @staticmethod def lengthOfLIS(nums: List[int]) -> int: """ 求最长递增子序列 """ tails = [0] * len(nums) size = 0 for num in nums: left, right = 0, size while left != right: mid = (left + right) // 2 if tails[mid] < num: left = mid + 1 else: right = mid tails[left] = num if left == size: size += 1 return size
本文作者:LARRY1024
本文链接:https://www.cnblogs.com/larry1024/p/16901322.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步