最长上升子序列(LIS)
最长上升子序列(LIS)
-
给定长度为
的序列 ,求序列中一个长度最长且递增的子序列。输出子序列的长度。 。
解法
-
设
为以 结尾的最长上升子序列的长度易知
的最大值为 区间 中的 小于 的最大的 加上1意思就是,
假设
为区间 中小于 的最大值,那么 就可以拼在 的后面,这时以 结尾的LIS的长度就为以 结尾的LIS长度+1用状态转移方程表示就是
-
用代码表示就是
int A[N+1]; int f[N+1]; for(int i = 1;i<=N;i++){ for(int j = 1;j<i;j++){ if(A[i] <= A[j]) continue; f[i] = max(f[i],f[j]+1); } } int max_ = -1; for(int i = 1;i<=N;i++) max_ = max(f[i],max_);
解法
-
设
为长度为 的上升子序列的最后一个数字设
为序列的第 个元素若
,则将 的值更新为相当于将长度为
的上升子序列的最后一位 改为了更小的 ,显然这样更有利于在后面接其他元素 -
但是目前遍历长为
的序列,对于其中每项 ,都需要进行至多 次操作去寻找合适的区间,时间复杂度仍然为 -
但是,由于
单调递增,可以在查找的时候使用二分查找来优化,这样就至多进行 次查找,时间复杂度降为 -
代码实现
int A[N+1]; int f[N+1]; int cnt = -1; //cnt代表当前最长上升子序列的长度 fill(f+1,f+N+1,1e9); //fill(st,ed,val)意为用val填充数组[st,ed)区间 //使用极大值填充区间 for(int i = 1;i<=N;i++){ int j = lower_bound(f+1,f+N+1,A[i]) - f; //lower_bound(st,ed,val)意为在[st,ed)区间内查找第一个不小于val的元素 //lower_bound返回一个指向找到元素的迭代器 //减去的f是地址 //地址 - 地址 = 下标 cnt = max(cnt,j); f[j] = A[i]; } int ans = cnt;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了