O(n ^ 2)
鉴于O(n ^ 2)的比较简单(就用了一个简单dp), 我就直接上代码了。
最长上升子序列:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | int dp[N]; int a[i];
 int lis(){
 int len = 0;
 for (int i = 1; i <= n; i++){
 dp[i] = 1;
 for (int j = 1; j < i; j++){
 if (a[j] < a[i])
 dp[i] = max(dp[i], dp[j] + 1);
 }
 len = max(len, dp[i]);
 }
 return len;
 }
 
 | 
最长不下降子序列
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | int lis(){int len = 0;
 for (int i = 1; i <= n; i++){
 dp[i] = 1;
 for (int j = 1; j < i; j++){
 if (a[j] <= a[i])
 dp[i] = max(dp[i], dp[j] + 1);
 }
 len = max(len, dp[i]);
 }
 return len;
 }
 
 | 
最长下降子序列
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | int lis(){int len = 0;
 for (int i = 1; i <= n; i++){
 dp[i] = 1;
 for (int j = 1; j < i; j++){
 if (a[j] > a[i])
 dp[i] = max(dp[i], dp[j] + 1);
 }
 len = max(len, dp[i]);
 }
 return len;
 }
 
 | 
最长不上升子序列
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | int lis(){int len = 0;
 for (int i = 1; i <= n; i++){
 dp[i] = 1;
 for (int j = 1; j < i; j++){
 if (a[j] >= a[i])
 dp[i] = max(dp[i], dp[j] + 1);
 }
 len = max(len, dp[i]);
 }
 return len;
 }
 
 | 
打印路径(n ^ 2)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | void lis_path(){ int len = 0,pos;
 for (int i = 1; i <= n; i++){
 dp[i] = 1;
 for (int j = 1; j < i; j++){
 if (a[j] < a[i] && dp[i] < dp[j] + 1){
 dp[i] = dp[j] + 1;
 path[i] = j;
 if (len < dp[i]){
 len = dp[i];
 pos = i;
 }
 }
 }
 
 }
 cout << len << "\n";
 int ans[1000];
 for (int i = len; i >= 1; i --){
 ans[i] = a[pos];
 pos = path[pos];
 }
 for (int i = 1; i <= len; i++){
 cout << ans[i] << ' ';
 }
 cout << "\n";
 }
 
 | 
O(n logn)
dp[i]存的是上升子序列长度为i的最小的一位数字
这样子dp数组一定是单调的(自己实践下)
初始时DP[1] = a[1], 从i = 2时遍历原数列, 将每个遍历的数与DP数列的末尾进行比较, 如果大于末尾, 则把DP数列长度提1将a[i]放在DP数列的最后, 如果小于末尾那么替换掉DP数列中比a[i]大的第一个数。
结束后DP数列的长度就是LIS的长度。
举个例子:
对于序列1,5,8,3,6,7来说,当子序列为1,5,8时,遇到3时,序列已经不能继续变长了。但是,我们可以通过替换,使“整个序列”看上去更小,从而有更大的机会去变长。这样,当替换5-3和替换8-6完成后(此时序列为1,3,6),我们可以在序列末尾添加一个7了。
最长上升子序列:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | int lis(){int len = 1,pos;
 dp[1] = a[1];
 for (int i = 2; i <= n; i++){
 if (a[i] > dp[len])
 dp[++len] = a[i];
 else
 *lower_bound(dp + 1, dp + len + 1, a[i]) = a[i];
 }
 return len;
 }
 
 | 
最长不下降子序列
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | int lis(){int len = 1,pos;
 dp[1] = a[1];
 for (int i = 2; i <= n; i++){
 if (a[i] >= dp[len])
 dp[++len] = a[i];
 else
 *upper_bound(dp + 1, dp + len + 1, a[i]) = a[i];
 }
 return len;
 }
 
 | 
最长下降子序列
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | int lis(){int len = 1,pos;
 dp[1] = a[1];
 for (int i = 2; i <= n; i++){
 if (a[i] < dp[len])
 dp[++len] = a[i];
 else
 *lower_bound(dp + 1, dp + len + 1, a[i], greater<int>() ) = a[i];
 }
 return len;
 }
 
 | 
最长不上升子序列
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | int lis(){int len = 1,pos;
 dp[1] = a[1];
 for (int i = 2; i <= n; i++){
 if (a[i] <= dp[len])
 dp[++len] = a[i];
 else
 *upper_bound(dp + 1, dp + len + 1, a[i], greater<int>() ) = a[i];
 }
 return len;
 }
 
 | 
打印路径(n logn)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | void lis_path(){  int len = 1;
 dp[1] = a[1];
 path[1] = 1;
 for (int i = 2; i <= n; i++){
 if (a[i] > dp[len]){
 dp[++len] = a[i];
 path[i] = len;
 }
 else{
 int cnt = lower_bound(dp + 1, dp + len + 1, a[i]) - dp;
 path[i] = cnt;
 dp[cnt] = a[i];
 }
 }
 cout << len << "\n";
 int cnt = len;
 for (int i = n; i >= 1; i--){
 if (path[i] == cnt)
 ans[cnt--] = a[i];
 if (cnt == 0)
 break;
 }
 for (int i = 1; i <= len; i++){
 cout << ans[i] << " ";
 }
 putchar(10);
 }
 
 | 
| 1
 | 恰似你一低头的温柔,娇弱水莲花不胜寒风的娇羞, 我的心为你悸动不休。  
 | 
原文作者: Mingfu Yan
原文链接: https://solodance.top/2020/06/26/lis总结/
版权声明: 转载请注明出处(必须保留作者署名及链接)