1. 题目来源
链接:300. 最长递增子序列
前导题:[线性dp] 最长上升子序列(模板题+最长上升子序列模型+LCS转化LIS)
2. 题目解析
很经典的一道题,重点在于其 O ( n l o g n ) O(nlogn) O(nlogn) 的写法。
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)、 O ( n l o g n ) O(nlogn) O(nlogn)
- 空间复杂度: O ( n ) O(n) O(n)
常规 O ( n 2 ) O(n^2) O(n2):
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> f(n);
for (int i = 0; i < n; i ++ ) {
f[i] = 1;
for (int j = 0; j < i; j ++ )
if (nums[i] > nums[j])
f[i] = max(f[i], f[j] + 1);
}
return *max_element(f.begin(), f.end());
}
};
朴素二分, O ( n l o g n ) O(nlogn) O(nlogn):
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> f(n + 1); // 0~n 长度
int cnt = 0;
for (int i = 0; i < n; i ++ ) {
int l = 0, r = cnt;
while (l < r) {
int mid = l + r + 1 >> 1;
if (f[mid] < nums[i]) l = mid;
else r = mid - 1;
}
f[r + 1] = nums[i];
cnt = max(cnt, r + 1);
}
return cnt;
}
};
STL贪心+二分 O ( n l o g n ) O(nlogn) O(nlogn) :
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> f;
for (auto &e : nums) {
if (f.empty() || e > f.back()) f.push_back(e);
int t = lower_bound(f.begin(), f.end(), e) - f.begin();
f[t] = e;
}
return f.size();
}
};
评论区大佬,三行,注意一开始得初始化大小,不然直接解引用 lower_bound()
可能会出错:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> d(nums.size(), INT_MAX);
for (auto num : nums) *lower_bound(d.begin(), d.end(), num) = num;
return lower_bound(d.begin(), d.end(), INT_MAX) - d.begin();
}
};
// 也行
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> f(nums.size(), 1e9);
for (auto &e : nums) *lower_bound(f.begin(), f.end(), e) = e;
return lower_bound(f.begin(), f.end(), 1e9) - f.begin();
}
};