O(n ^ 2)
鉴于O(n ^ 2)的比较简单(就用了一个简单dp), 我就直接上代码了。
最长上升子序列:
1 2 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; }
|
最长不下降子序列
1 2 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; }
|
最长下降子序列
1 2 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; }
|
最长不上升子序列
1 2 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)
1 2 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了。
最长上升子序列:
1 2 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; }
|
最长不下降子序列
1 2 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; }
|
最长下降子序列
1 2 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; }
|
最长不上升子序列
1 2 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)
1 2 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总结/
版权声明: 转载请注明出处(必须保留作者署名及链接)