最长递增子序列 (LIS) Longest Increasing Subsequence

问题描述:

有一个长为n的数列a0, a1,..., an-1.请求出这个序列中最长的上升子序列。请求出这个序列中最长的上升子序列。

上升子序列:对于任意i<j都满足ai<aj的子序列.

限制条件

i <= n <= 1000

0 <= ai <= 1000000

两种定义方式 具体看程序注释

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 #define INF 0x3f3f3f3f
 6 using namespace std;
 7
 8 int n;
 9 int a[128];
10 //定义 dp[i] 以a[i]作为最末数字的的最长子序列
11 //状态转移方程 dp[i] = 1//自己
12 //                   = max(dp[i], dp[j]+1) //i > j && a[i] > a[j] 将a[i] 添加在a[j]后面
13 int main()
14 {
15     freopen("in.txt", "r", stdin);
16     scanf("%d", &n);
17     for (int i = 0; i < n; i++)
18     {
19         scanf("%d", &a[i]);
20     }
21     int dp[128];
22     memset(dp, 0, sizeof(dp));
23     for (int i = 0; i < n; i++)
24     {
25         dp[i] = 1;
26         for (int j = 0; j < i; j++)
27         {
28             if (a[j] < a[i]) dp[i] = max(dp[i], dp[j]+1);
29         }
30     }
31     cout << dp[n-1] << endl;
32     //复杂度 O(n^2)
33     //---------------------------------------------------------------------------//
34     //定义dp[i] 长度为i+1 的序列 的最小结尾值 因为结尾值最小 在后面更新时 越有优势
35     //状态转移方程 dp[i] = min(dp[i], a[j])
36     fill(dp, dp+128, INF);
37     for (int j = 0; j < n;j++)//注意是要对每一个数从前往后只检查一次 去看能否替换 dp数列中的某个值
38     {
39         for (int i = 0; i < n; i++)
40         {
41             if (i == 0 || dp[i-1] < a[j]) dp[i] = min(dp[i], a[j]);//因为是要求递增 那么比前一个大的话更新这一位 使这一位为最小值
42         }
43     }//这样实现也是O(n^2)的复杂度
44     //但是在查找a[j]的过程 可以使用二分查找 优化这样复杂度变为n*logN
45     int ans = 0;
46     for (int i = 0; i < n; i++)
47     {
48         if (dp[i] < INF) ans = i+1;
49     }
50     cout << ans << endl;
51     //--------------------------------------------------------------------//
52     fill(dp, dp+128, INF);
53     for (int i = 0; i < n; i++)
54     {
55         *lower_bound(dp, dp+n, a[i]) = a[i];//dp[0] 到 dp[n-1] >= a[i] 的最小指针 也就是按照从左到有的顺序
56     }
57     for (int i = 0; i < n; i++)
58     {
59         if (dp[i] < INF) ans = i+1;
60     }
61     cout << ans << endl;
62     return 0;
63 }
时间: 2024-10-08 22:26:33

最长递增子序列 (LIS) Longest Increasing Subsequence的相关文章

最长上升子序列LIS(Longest Increasing Subsequence)

算法1:时间复杂度:O(n^2):我们依次遍历整个序列,每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序列.我们用dp[i]来存放序列1-i的最长上升子序列的长度,那么dp[i]=max(dp[j])+1,(j∈[1, i-1]); 显然dp[1]=1,我们从i=2开始遍历后面的元素即可. #include<iostream> #include<algorithm> #include<stri

DP(dynamic programming)之LIS(longest increasing subsequence)问题(转)

今天回顾WOJ1398,发现了这个当时没有理解透彻的算法.看了好久好久,现在终于想明白了.试着把它写下来,让自己更明白. 最长递增子序列,Longest Increasing Subsequence 下面我们简记为 LIS.排序+LCS算法 以及 DP算法就忽略了,这两个太容易理解了. 假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5.下面一步一步试着找出它.我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列.此外,我们用一个变

算法--字符串:最长递增子序列LIS

转自:labuladong公众号 很多读者反应,就算看了前文 动态规划详解,了解了动态规划的套路,也不会写状态转移方程,没有思路,怎么办?本文就借助「最长递增子序列」来讲一种设计动态规划的通用技巧:数学归纳思想.  最长递增子序列(Longest Increasing Subsequence,简写 LIS)是比较经典的一个问题,比较容易想到的是动态规划解法,时间复杂度 O(N^2),我们借这个问题来由浅入深讲解如何写动态规划. 比较难想到的是利用二分查找,时间复杂度是 O(NlogN),我们通过

动态规划(DP),最长递增子序列(LIS)

题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(dp[k])+1,(k<i),(a[k]<a[i]) #include <stdio.h> #define MAX 1005 int a[MAX];///存数据 int dp[MAX];///dp[i]表示以a[i]为结尾的最长递增子序列(LIS)的长度 int main() { int

Leetcode之深度优先搜索(DFS)专题-DFS+记忆化 329. 矩阵中的最长递增路径(Longest Increasing Path in a Matrix)

Leetcode之深度优先搜索(DFS)专题-329. 矩阵中的最长递增路径(Longest Increasing Path in a Matrix) 深度优先搜索的解题详细介绍,点击 给定一个整数矩阵,找出最长递增路径的长度. 对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向上移动或移动到边界外(即不允许环绕). 示例 1: 输入: nums = [ [9,9,4], [6,6,8], [2,1,1] ] 输出: 4 解释: 最长递增路径为 [1, 2, 6, 9].

最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现

关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已经做了实现,但是这种方法时间复杂度太高,查阅相关资料后我发现有人提出的算法可以将时间复杂度降低为O(nlogn),这种算法的核心思想就是替换(二分法替换),以下为我对这中算法的理解: 假设随机生成的一个具有10个元素的数组arrayIn[1-10]如[2, 3, 3, 4, 7, 3, 1, 6,

动态规划系列【2】最长递增子序列LIS

Given an unsorted array of integers, find the length of longest increasing subsequence. For example, Given [10, 9, 2, 5, 3, 7, 101, 18], The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than

算法面试题 之 最长递增子序列 LIS

找出最长递增序列 O(NlogN)(不一定连续!) 参考 http://www.felix021.com/blog/read.php?1587%E5%8F%AF%E6%98%AF%E8%BF%9E%E6%95%B0%E7%BB%84%E9%83%BD%E6%B2%A1%E7%BB%99%E5%87%BA%E6%9D%A5 我就是理解了一下他的分析 用更通俗易懂的话来说说题目是这样 d[1..9] = 2 1 5 3 6 4 8 9 7 要求找到最长的递增子序列首先用一个数组b[] 依次的将d里面

POJ 1836 Alignment 最长递增子序列(LIS)的变形

大致题意:给出一队士兵的身高,一开始不是按身高排序的.要求最少的人出列,使原序列的士兵的身高先递增后递减. 求递增和递减不难想到递增子序列,要求最少的人出列,也就是原队列的人要最多. 1 2 3 4 5 4 3 2 1 这个序列从左至右看前半部分是递增,从右至左看前半部分也是递增.所以我们先把从左只右和从右至左的LIS分别求出来. 如果结果是这样的: A[i]={1.86 1.86 1.30621 2 1.4 1 1.97 2.2} //原队列 a[i]={1 1 1 2 2 1 3 4} b[