最长递增子序列(Longest Increasing Subsequence)
1. 问题描述
有一个序列 A = a[1:n], 若存在一个数列bm,其中对于任何1 < i < m ,满足bi < bi+1 且 abi < abi+1 ,则称abn为an的一个递增子序列
试求出给定序列的最长递增子序列长度。
2. 动态规划解
用 opt[i] 表示 A[1 : i] 的 以 Ai 为末位元素的最长递增子序列的长度,则
- opt[1] = 1
- 如果存在 1 <= j < i, 使得 Aj < Ai, 则 opt[i] = max {opt[j] + 1 | 1 <= j < i, Aj < Ai}
- 如果 Ai < Aj( for all 1 <=j <i), 则 opt[i] = 1
3. c++实现
// Longest Increasing Sequence template<class Iter, class Compare> int LIS(Iter beg, Iter end, Compare op) { if(beg == end) return 0; int n = end - beg; std::vector<int> opt(n); opt[0] = 1; Iter id = std::next(beg); for(int i = 1; i < n; ++i, ++id) { opt[i] = 1; Iter iter = beg; for(int j = 0; j < i; ++iter, ++j) if(op(*iter, *id) && opt[i] < opt[j] + 1 ) opt[i] = opt[j] + 1; } int length_opt = std::accumulate(opt.begin(), opt.end(), 0, [](int a, int b){return a > b ? a : b;}); return length_opt; } template<class Iter> int LIS(Iter beg, Iter end) { return LIS(beg, end, std::less<decltype(*beg)>()); }
4. 分析
时间复杂度 O(n^2)
空间复杂度 O(n)
5. O(n * lg(n))解法
生成数组 B , B[i] 存放 A 的所有的长度为 i 的递增子序列中,最末位元素的最小值。
template<class Iter, class Compare> int LIS2(Iter beg, Iter end, Compare op) { if(beg == end) return 0; std::vector<typename std::iterator_traits<Iter>::value_type> B; B.reserve(end - beg); B.push_back(*beg++); for(; beg != end; ++beg) { auto it = std::upper_bound(B.begin(), B.end(), *beg, op); if(it != B.end()) *it = *beg; else B.push_back(*beg); } return B.size(); } template<class Iter> int LIS2(Iter beg, Iter end) { return LIS2(beg, end, std::less<decltype(*beg)>()); }
老实为人,踏实为学

浙公网安备 33010602011771号