最長上升子序列(LIS):
定義:
最長上升子序列(LIS)是一個序列中,找到一個子序列,使得這個子序列的元素是嚴格遞增的,且該子序列的長度最大
*子串和子序列的差別:
子串: 元素的連續性,必須是相鄰的
子序列:元素的相對順序,可以不連續
從例項中來
[1, 7, 5, 6, 9, 2, 4] 這個陣列根據肉眼掃描法不難發現出LIS是[1, 5, 6, 9]長度最長為4
對於這個長度如何求解出來, 有著這幾個經典解法去求解
動態規劃 複雜度O(n ^ 2):
在計算LIS的最長長度的時候, 某些元素a[i]是LIS的一部分, 那麼a[i]以前的, 元素所有小於a[i]的元素所構成的LIS的長度就是最優的 對於動態規劃來說, 為了避免
重複問題的重複計算, 可以快取下dp[i]當前的值, dp[i]儲存的就是a[i]為結尾的最長長度, 那麼這個序列的最長長度只需去求當前dp[i]陣列的最大值即可
Code:
void LIS_dp() { int n; cin >> n; vector <int> a(n + 1); for (int i = 1; i <= n; i++) { cin >> a[i]; } vector <int> dp(n + 1, 1); for (int i = 1; i <= n; i++) { for (int j = 1; j < i; j++) { if (a[i] > a[j]) { dp[i] = max(dp[i], dp[j] + 1); } } } cout << *max_element(dp.begin() + 1, dp.end()) << '\n'; }
二分 複雜度(n * logn)
透過記錄一個ans陣列, ans[i]表示當前找到的長度為i + 1的上升子序列的末尾元素, ans.size()表示當前最長上升子序列的最長長度
操作:
Code:
void LIS_lower_bound() { int n; cin >> n; vector <int> ans; for (int i = 1; i <= n; i++) { int x; cin >> x; if (ans.empty() || x > ans.back()) { ans.emplace_back(x); } else { auto it = lower_bound(ans.begin(), ans.end(), x) - ans.begin(); ans[it] = x; } } cout << ans.size() << '\n'; }
2