1、动态规划法
我们利用数组dp记录以每一位为结尾的子序列中最长递增子序列的长度。很显然,我们可以得到递增方程为: d p [ i ] = m a x ( d p [ i ] , d p [ j ] + 1 ) dp[i]=max(dp[i],dp[j]+1) dp[i]=max(dp[i],dp[j]+1),其中j是0到i中间的每一位。最终我们遍历整个dp数组即可得到最大值。时间复杂度为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( n ) O(n) O(n)。
class Solution {
public:
int lengthOfLIS(vector<int> &nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
vector<int> dp(n, 0);
for (int i = 0; i < n; ++i) {
dp[i] = 1;
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};
2、二分查找
我们可以维护一个数组d用于记录当前递增子序列中每一位上的最小元素,同时使用变量length记录子序列的长度。每当我们读入一个新的数时:1、若新元素大于当前数组的末尾元素,说明新元素可以加入当前的递增子序列中,因此直接加入数组d并将长度加一;2、若新元素小于等于当前数组的末尾元素,说明新元素不能加入当前数组,我们可以使用二分查找在当前数组中寻找第一个比新元素小的数字并将他的后一位进行替换。时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度为 O ( n ) O(n) O(n)。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = 1, n = nums.size();
if (n == 0) {
return 0;
}
vector<int> d(n + 1, 0);
d[len] = nums[0];
for (int i = 1; i < n; ++i) {
if (nums[i] > d[len]) {
d[++len] = nums[i];
} else {
int l = 1, r = len, pos = 0;
while (l <= r) {
int mid = (l + r) >> 1;
if (d[mid] < nums[i]) {
pos = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
d[pos + 1] = nums[i];
}
}
return len;
}
};