Longest Increasing Subsequence
Longest Increasing Subsequence 问题指的是在一个给定的Array中寻找所有元素都递增的Subsequence中最长的
Naive Approach
Time Complexity: $O(n^2)$
假设 dp[i] 是以 a_i 结尾的 LIS 长度
那样 ans = dp 中最大的那个
Transition
**dp[i] =**
**max(dp[j] + 1)** where a[j] < a[i]
尝试把新的
**a[i]**接在现有的LIS后面
4 5 3 2 9 8 7
dp[0] = 1
从 4 开始 如果今天4
Code
1 | vector<int> a, ans, parent; |
Approach 2 - Binary Search
Observation
LIS中的元素必定是Sorted了的,由小至大
State
$$
dp[i]=len
$$
**a[1..n]**: 原始序列**dp[k]**: 长度为k的LIS末尾元素的最小值**len**: 当前已知的最长子序列的长度
Transistion
- 每次操作时均替换掉最有可能被替换掉的元素,
也就是第一个大于等于要放入的元素的元素lower_bound—— $O(\log{n})$ - 如果这个元素大于LIS里的任一一个元素,那么替换相当于放入多一个元素
反之,替换之后不影响当前的长度
意义
这样的操作降低了未来元素变成“Increasing”的难度,
新的元素更容易变成 Increasing,也更容易Append多一个元素在LIS末端替换的过程相当于开另一条subseqeunce
替换的元素之前的保持一样,之后的则放弃掉
之后的过程相当于接上新的Subsequence
如此存取的**dp**并不是LIS本体,基本上也不太可能通过GetPath的方式回溯相关的LIS
Time Complexity
$O(n\log{n})$
Code
1 | void solve(){ |
Problems
Approach 3 - Segment Tree
Intuition
计算 max 的时间花太多了,可以改用 Segment Tree 来节省
空间也不需要到 2D,可以直接压缩在1D
Normalization
Map the values in array into range [1-N] by increasing sequence
State
**dp[i]** =
Length of LIS ending with element **j** (after Normalization)
Transistion
Manage **dp** array with Segment Tree (as underlying array)
**dp[a[i]] = query(1, a[i] - 1) + 1**
Update with the maximum of prefix dp[1..a[j-1]] + 1
(Adding 1 element to the end of LIS)
Answer
**query(1, n)**
The Maximum length of LIS considering from which ending with element 1 to N respectively
Time Complexity
$\text{O}(n\log{n})$
Code
1 | class SegmentTree { |