最长上升子序列两种求解方法
c++
最长上升子序列 II
/* * 最长上升子序列 * * 问题描述: * 给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。 * 1 ≤ N ≤ 1000, * −10^9 ≤ 数列中的数 ≤ 10^9 * * 1 ≤ N ≤ 100000 该题目还可以进一步扩大范围 * * 算法思路1: * 数组定义 * f[i] 表示以 a[i] 为结尾的,严格单调递增的子序列长度 * 递归公式 * f[i] = max(f[j] + 1, j < i 并且 a[j] < a[i] * 复杂度 * O(N ^ 2) * * 算法思路2: * 数组定义 * f[i] 表示当前长度为 i 的递增子序列的最小末尾 * 性质推理 * f[i] 数组是严格单调递增的,倘若存在 f[i] >= f[i + 1],那额就说明 f[i + 1] 这个方案是可以更新 f[i] 使其更小的。 * 那么,如何更新维护这个数组呢? * 拿到 a[i] 二分查询 f[i],找到小于 a[i] 的最大 f[j],更新f[j + 1],因为小于等于 j 的无法更新,大于 j + 1的也无法, * 只能顺着 j 更新 j + 1 * 复杂度 * O(N log N) * */ #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cmath> #include <vector> using namespace std; const int N = 100010; const int INF = 0x3f3f3f3f, _INF = 0xcfcfcfcf; int f[N], a[N], n; int solution_one() { int ret = 1; for (int i = 1; i <= n; i ++ ) { f[i] = 1; for (int j = 1; j < i; j ++ ) { if (a[j] < a[i]) { f[i] = max(f[i], f[j] + 1); } } ret = max(ret, f[i]); } return ret; } int solution_two() { memset(f, 0x3f, sizeof f); f[0] = _INF; int len = 0; int l, r, mid; for (int i = 1; i <= n; i ++ ) { l = 0, r = len; while (l < r) { mid = (l + r + 1) >> 1; if (f[mid] < a[i]) { l = mid; } else { r = mid - 1; } } f[l + 1] = a[i]; len = max(len, l + 1); } return len; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++ ) { scanf("%d", &a[i]); } int res = solution_two(); printf("%d\n", res); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)