[LeetCode] 300. Longest Increasing Subsequence 最长递增子序列
Given an unsorted array of integers, find the length of longest increasing subsequence.
Example:
Input:[10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is[2,3,7,101]
, therefore the length is4
.
Note:
- There may be more than one LIS combination, it is only necessary for you to return the length.
- Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> dp(nums.size(), );
int res = ;
for (int i = ; i < nums.size(); ++i) {
for (int j = ; j < i; ++j) {
if (nums[i] > nums[j]) {
dp[i] = max(dp[i], dp[j] + );
}
}
res = max(res, dp[i]);
}
return res;
}
};
下面来看一种优化时间复杂度到 O(nlgn) 的解法,这里用到了二分查找法,所以才能加快运行时间哇。思路是,先建立一个数组 ends,把首元素放进去,然后比较之后的元素,如果遍历到的新元素比 ends 数组中的首元素小的话,替换首元素为此新元素,如果遍历到的新元素比 ends 数组中的末尾元素还大的话,将此新元素添加到 ends 数组末尾(注意不覆盖原末尾元素)。如果遍历到的新元素比 ends 数组首元素大,比尾元素小时,此时用二分查找法找到第一个不小于此新元素的位置,覆盖掉位置的原来的数字,以此类推直至遍历完整个 nums 数组,此时 ends 数组的长度就是要求的LIS的长度,特别注意的是 ends 数组的值可能不是一个真实的 LIS,比如若输入数组 nums 为 {4, 2, 4, 5, 3, 7},那么算完后的 ends 数组为 {2, 3, 5, 7},可以发现它不是一个原数组的 LIS,只是长度相等而已,千万要注意这点。参见代码如下:
解法二:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if (nums.empty()) return ;
vector<int> ends{nums[]};
for (auto a : nums) {
if (a < ends[]) ends[] = a;
else if (a > ends.back()) ends.push_back(a);
else {
int left = , right = ends.size();
while (left < right) {
int mid = left + (right - left) / ;
if (ends[mid] < a) left = mid + ;
else right = mid;
}
ends[right] = a;
}
}
return ends.size();
}
};
我们来看一种思路更清晰的二分查找法,跟上面那种方法很类似,思路是先建立一个空的 dp 数组,然后开始遍历原数组,对于每一个遍历到的数字,用二分查找法在 dp 数组找第一个不小于它的数字,如果这个数字不存在,那么直接在 dp 数组后面加上遍历到的数字,如果存在,则将这个数字更新为当前遍历到的数字,最后返回 dp 数组的长度即可,注意的是,跟上面的方法一样,特别注意的是 dp 数组的值可能不是一个真实的 LIS。参见代码如下:
解法三:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> dp;
for (int i = ; i < nums.size(); ++i) {
int left = , right = dp.size();
while (left < right) {
int mid = left + (right - left) / ;
if (dp[mid] < nums[i]) left = mid + ;
else right = mid;
}
if (right >= dp.size()) dp.push_back(nums[i]);
else dp[right] = nums[i];
}
return dp.size();
}
};
下面来看两种比较 tricky 的解法,利用到了 C++ 中 STL 的 lower_bound 函数,lower_bound 返回数组中第一个不小于指定值的元素,跟上面的算法类似,还需要一个一维数组v,然后对于遍历到的 nums 中每一个元素,找其 lower_bound,如果没有 lower_bound,说明新元素比一维数组的尾元素还要大,直接添加到数组v中,跟解法二的思路相同了。如果有 lower_bound,说明新元素不是最大的,将其 lower_bound 替换为新元素,这个过程跟算法二的二分查找法的部分实现相同功能,最后也是返回数组v的长度,注意数组v也不一定是真实的 LIS,参见代码如下:
解法四:
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();
}
};
既然能用 lower_bound,那么 upper_bound 就耐不住寂寞了,也要出来解个题。upper_bound 是返回数组中第一个大于指定值的元素,和 lower_bound 的区别时,它不能返回和指定值相等的元素,那么当新进来的数和数组中尾元素一样大时,upper_bound 无法返回这个元素,那么按算法三的处理方法是加到数组中,这样就不是严格的递增子串了,所以要做个处理,在处理每个新进来的元素时,先判断数组v中有无此元素,有的话直接跳过,这样就避免了相同数字的情况,参见代码如下:
解法五:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> v;
for (auto a : nums) {
if (find(v.begin(), v.end(), a) != v.end()) continue;
auto it = upper_bound(v.begin(), v.end(), a);
if (it == v.end()) v.push_back(a);
else *it = a;
}
return v.size();
}
};
还有一种稍微复杂点的方法,参见我的另一篇博客 Longest Increasing Subsequence,那是 LintCode 上的题,但是有点不同的是,那道题让求的 LIS 不是严格的递增的,允许相同元素存在。
Github 同步地址:
https://github.com/grandyang/leetcode/issues/300
类似题目:
Increasing Triplet Subsequence
Number of Longest Increasing Subsequence
Minimum ASCII Delete Sum for Two Strings
参考资料:
https://leetcode.com/problems/longest-increasing-subsequence/
[LeetCode] 300. Longest Increasing Subsequence 最长递增子序列的更多相关文章
- [leetcode]300. Longest Increasing Subsequence最长递增子序列
Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Inp ...
- LeetCode 300. Longest Increasing Subsequence最长上升子序列 (C++/Java)
题目: Given an unsorted array of integers, find the length of longest increasing subsequence. Example: ...
- leetcode300. Longest Increasing Subsequence 最长递增子序列 、674. Longest Continuous Increasing Subsequence
Longest Increasing Subsequence 最长递增子序列 子序列不是数组中连续的数. dp表达的意思是以i结尾的最长子序列,而不是前i个数字的最长子序列. 初始化是dp所有的都为1 ...
- [LeetCode] Longest Increasing Subsequence 最长递增子序列
Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...
- [LintCode] Longest Increasing Subsequence 最长递增子序列
Given a sequence of integers, find the longest increasing subsequence (LIS). You code should return ...
- 673. Number of Longest Increasing Subsequence最长递增子序列的数量
[抄题]: Given an unsorted array of integers, find the number of longest increasing subsequence. Exampl ...
- 300 Longest Increasing Subsequence 最长上升子序列
给出一个无序的整形数组,找到最长上升子序列的长度.例如,给出 [10, 9, 2, 5, 3, 7, 101, 18],最长的上升子序列是 [2, 3, 7, 101],因此它的长度是4.因为可能会有 ...
- poj 2533 Longest Ordered Subsequence 最长递增子序列
作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4098562.html 题目链接:poj 2533 Longest Ordered Subse ...
- [LeetCode] Number of Longest Increasing Subsequence 最长递增序列的个数
Given an unsorted array of integers, find the number of longest increasing subsequence. Example 1: I ...
随机推荐
- 【转】Python zip() 函数
转自:http://www.runoob.com/python/python-func-zip.html 描述 zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回 ...
- matplotlib动态绘图
目录 package Process 解决中文乱码问题 simple_plot() scatter_plot() three_dimension_scatter() Jupyter notebook ...
- Python连载41-yield from详解、委派生成器
一. 1.yield from (1)调用协程为了得到返回值,协程必须正常终止 (2)生成器正常终止会发出StopIteration异常,异常对象的value属性保存返回值. (3)yield fro ...
- CDN的智能调度,链路优化的详细解答
您的用户在请求资源的过程中,可能受到网络.地域.带宽等影响,无法保证请求一定是按照最优访问路径进行传递,猫云 CDN 通过对全网链路进行实时监控,结合自研的 GSLB 调度体系和智能路由技术,从以下几 ...
- python3爬虫筛选所需要数据
第一次使用博客园,也是第一篇文章,让我们一起开启学习之旅吧!! 昨天在为某授权系统做安全性测试的时候,可以未授权访问系统的用户登陆统计记录.由此想整理出部分用户名,作为暴力破解的用户名,检查是否存在用 ...
- Tensorflow faster rcnn系列一
注意:本文主要是学习用,发现了一个在faster rcnn训练流程写的比较详细的博客. 大部分内容来自以下博客连接:https://blog.csdn.net/weixin_37203756/arti ...
- 一个简单的利用 WebClient 异步下载的示例(三)
继续上一篇 一个简单的利用 WebClient 异步下载的示例(二) 后,继续优化它. 1. 直接贴代码了: DownloadEntry: public class DownloadEntry { p ...
- Kubernetes 有状态与无状态介绍
Kubernetes 有状态与无状态介绍 无状态:deployment - 认为所有pod都是一样的,不具备与其他实例有不同的关系. - 没有顺序的要求. - 不用考虑再哪个Node运行. - 随意扩 ...
- Spring源码系列 — 注解原理
前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...
- FreeMarker实现网页静态化
1.FreeMarker实现网页静态化. FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与Web容器无关,即在Web运行时,它并不知道Servl ...