问题描述:
例:一个数组为[4, 5, 6 , 3]则最长的递增子序列为4 , 5, 6.
方法1:
动态规划, dp[i]代表一nums[i]结尾的,递增子序列的最长长度
dp[i] = max(dp[i], dp[j]+1), j的取值范围是0到i - 1,所以时间复杂度是O(n^2)
int lengthOfLIS(vector<int>& nums) {
if (nums.empty())
return 0;
vector<int> dp(nums.size(), 1);
int ans = 1;
for (int i = 1; i < nums.size(); ++i) {
for (int j = i - 1; j >= 0; --j) {
if (nums[i] > nums[j])
dp[i] = max(dp[i], dp[j] + 1);
}
ans = max(ans, dp[i]);
}
return ans;
}
方法2:
定义一个数组tails, tails[i]代表的是长度为i+1的子序列的最小结尾。
例:[4, 5, 6 , 3],
len = 1 : [4], [5], [6], [3] => tails[0] = 3
len = 2 : [4, 5], [5, 6] => tails[1] = 5
len = 3 : [4, 5, 6] => tails[2] = 6
证明tails数组时递增的,假设tails[i - 1] > tails[i],那么就存在一个数以其结尾长度为i,但是小于tails[i - 1],与定义矛盾。
更新方法:
1.如果nums[i]大于tails.back(),那么在tails后面加一个数。
2. tails[i-1] <= nums[i] <= tails[i],那么更新tails[i] = nums[i];
int lengthOfLIS(vector<int>& nums) {
vector<int> tails; //tails[i]代表长度为i+1的子序列的最小结尾
for(int i = 0; i < nums.size(); ++i){
auto iter = std::lower_bound(tails.begin(), tails.end(), nums[i]);
if(iter == tails.end())
tails.push_back(nums[i]);
else
*iter = nums[i];
}
return tails.size();
}
ps:
//lower_bound返回指向第一个大于等于nums[i]的迭代器,没有则返回talis.end()
auto iter = lower_bound(tails.begin(), tails.end(), nums[i]);
//upper_bound返回第一个大于nums[i]的迭代器,没有则返回tails.end()
auto iter = upper_bound(tails.begin(), tails.end(), nums[i]);