首页 > 代码库 > 最长递增子序列 (LIS) Longest Increasing Subsequence

最长递增子序列 (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 }

 

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