原题: https://leetcode-cn.com/problems/longest-increasing-subsequence/
O(n^2)的做法不赘述, https://www.cnblogs.com/grandyang/p/4938187.html 提到了O(nlogn)的解法如下:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> v;
for (auto a : nums) {
auto it = lower_bound(v.begin(), v.end(), a);
if (it == v.end()) v.push_back(a);
else *it = a;
}
return v.size();
}
};
解法遍历了数组nums, 并维护了一个辅助数组, 本文将阐述辅助数组的定义, 以及其有效性的证明.
辅助数组v的定义如下:
当算法遍历到第n个元素时, 辅助数组里的第i个元素的含义为:
维护的是在第[0, n-1]个元素中, 要维护长度为i的递增子序列时, 结尾元素的最小值.
这个辅助数组v是递增的, 此处用反证法进行证明:
设辅助数组v有两个元素v[i]和v[j], i < j.
假如v[i] >= v[j], 则对于v[j]所对应的长度为j的递增序列, 其v[j-1]一定小于v[j], 于是有v[j-1] < v[j] <= v[i].
那么数组v的第i个元素值应当为v[j-1]了, 出现矛盾.
为什么要用lower_bound而不是upper_bound寻找替代点呢? 因为要维护辅助数组的递增特性, 如果用upper_bound取到的是大于遍历元素a的元素, 而在它之前有中有等于a的元素,则替换后会有两个等于a的元素, 破坏了递增的特性.