300. 最长递增子序列
给定一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
最后一步:在最优策略中,最长严格递增子序列一定存在着最后一个元素nums[i]。
虽然我们不知道是哪个字符,但是肯定有最后一个元素。
那么,有了最后一个字符之后,我们发现这里存在着两种情况(考虑序列长度大于2的条件下):
第一种情况:最优策略中的最后一个元素 nums[i] 小于前面一个元素 nums[i - 1],这时最值取决于前面一个元素 nums[i - 1] 结尾的序列,这种情况不属于递增,可以直接跳过。
第二种情况:大于,这时候由于题目不要求子序列是连续的,因此我们需要枚举最后一个字符前面的所有元素进行比较,得到最长的递增子序列,然后加上 nums[i]。
由此,我们发现:
需要求以 nums[i - 1] 结尾的序列的最长递增子序列
而原问题是求以 nums[i] 结尾的序列的最长递增子序列
问题规模缩小了
状态定义:设 f[i] 是以 nums[i] 结尾的序列的最长递增子序列的长度。
如何设定状态?根据题目中的要求,如果是求长度,那么我们需要将状态的宾语设定为长度。
f[i] = max( f[i], f[j] + 1) for j in [0, i) 且 nums[i] > nums[j]
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
int result = 1;
// 定义并初始化状态方程
vector<int> f(n, 1);
for (int i = 0; i < n; ++i) {
// f[i] = 1;
// 在子问题中,只有最后一个元素与前面的每一个元素都进行对比
// 这里和674题的连续不同:仅仅需要比较前一个元素就能确保最长
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
f[i] = max(f[i], f[j] + 1);
}
}
if (f[i] > result) {
result = f[i];
}
}
return result;
}
};
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> f(n, 1);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
f[i] = max(f[i], f[j] + 1);
}
}
}
return *max_element(f.begin(), f.end());
}
};
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = 1, n = (int)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; // 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 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;
}
};
// 作者:LeetCode-Solution
// 链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/zui-chang-shang-sheng-zi-xu-lie-by-// leetcode-soluti/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> res(1);
res[0] = nums[0];
for(int i = 1; i < nums.size(); ++i) {
if (nums[i] > res[res.size() - 1]) {
res.emplace_back(nums[i]);
}
// 使用二分查找
else {
int left = 0, right = res.size() - 1;
while (left < right) {
// int mid = (left + right) >> 1;
int mid = (left + right) / 2;
if (res[mid] < nums[i]) {
left = mid + 1;
}
else {
right = mid;
}
}
// 用当前元素覆盖掉 >= 它的元素中最小的那个。
res[left] = nums[i];
}
}
return res.size();
}
};
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> res;
for(auto n : nums) {
auto lb = lower_bound(res.begin(), res.end(), n);
if(lb == res.end()) {
res.push_back(n);
}
else {
res[lb - res.begin()] = n;
}
}
return res.size();
}
};