LeetCode 300. Longest Increasing Subsequence最长上升子序列 (C++/Java)
题目:
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?
分析:
给定一个无序的整数数组,找到其中最长上升子序列的长度。
注意此题不要求上升子序列是连续的,我们可以去观察这样一个问题,已知一个序列[16,17,2,3,4]其最大上升子序列是[2,3,4]如果这时候又来一个20,我们这样来看。
如果以4为结尾和20组合,那么我们此时的序列则是[16,17,2,3,4,20]其最大上升子序列是[2,3,4,20],最大长度也就是3+1=4(原来序列以4为结尾的最大上升子序列的长度+1)。
如果以3为结尾和20组合,那么我们此时的序列则是[16,17,2,3,20]其最大上升子序列是[2,3,20],最大长度是2+1。
如果以2为结尾和20组合,那么我们此时的序列则是[16,17,2,20]其最大上升子序列是[2,20],最大长度是1+1。
你可能会问这时候最大上升子序列不应该是[16,17,20]吗?要记住,此时我们求的是以2结尾的最大上升子序列,所以只能是[2,20]。
如果以17为结尾和20组合,那么我们此时的序列则是[16,17,20]其最大上升子序列是[16,17,20],最大长度是2+1。
如果以16为结尾和20组合,那么我们此时的序列则是[16,20]其最大上升子序列是[16,20],最大长度是1+1。
我们可以从头遍历数组,每新来一个元素,便去和以前所有元素去相比,如果新来的元素比当前元素大,则意味着新来的元素可以和以当前元素为结尾的最大上升子序列构成新的最大上升子序列,且新最大上升子序列的长度等于以当前元素为结尾的最大上升子序列的长度+1,这样听起来可能绕口些。我们开辟一个新的数组,大小和原数组一样大,对应位置存储着以此元素为结尾的最大上升子序列的长度。
| 10 | |||||||
| 1 | |||||||
| 10 | 9 | ||||||
| 1 | 1 | ||||||
| 10 | 9 | 2 | |||||
| 1 | 1 | 1 | |||||
| 10 | 9 | 2 | 5 | ||||
| 1 | 1 | 1 | 2 | ||||
| 10 | 9 | 2 | 5 | 3 | |||
| 1 | 1 | 1 | 2 | 3 | |||
| 10 | 9 | 2 | 5 | 3 | 7 | ||
| 1 | 1 | 1 | 2 | 2 | 3 | ||
| 10 | 9 | 2 | 5 | 3 | 7 | 101 | |
| 1 | 1 | 1 | 2 | 2 | 3 | 4 | |
| 10 | 9 | 2 | 5 | 3 | 7 | 101 | 18 |
| 1 | 1 | 1 | 2 | 2 | 3 | 4 | 4 |
每新来一个元素,都要和前面的每一个元素为结尾的序列去比较能否成为新的上升子序列。最后返回数组中最大的值,即是最大上升子序列的长度,这样时间复杂度是O(n^2)。
现在我们再来说一下O(nlogn)的方法,我们来利用二分搜索来维护一个最有希望的上升子序列的数组dp。
我们知道如果一个序列,[10,20,30,1,2,3.....],很明显1,2,3要比10,20,30更有希望构成最大上升子序列。
给定数列[10,20,30,1,2,3,5]。
先来10,那么此时的最有希望的上升子序列dp:[10].
20,dp:[10,20]
30,dp:[10,20,30]
此时新加进来1,利用二分搜素,将1替换掉10,此时的最有希望的上升子序列为[1,20,30],你可能会问,1在30的后面,无法和20,30构成上升子序列,的确,但是我们要求的是最有希望的,且我们的数组的大小就是最大的上升子序列的长度,如果后面的元素无法构成更大的上升子序列,那么当前数组的大小也已经记录下之前的最大上升子序列的长度,这点不用担心。
1,dp:[1,20,30]
2,dp:[1,2,30]
3,dp:[1,2,3]
5,dp:[1,2,3,5]
此时的dp正是我们求的最有希望的上升子序列,且它的长度正是最大上升子序列的长度。
如果数列是[10,20,30,1,2]
最后求的dp会是[1,2,30],虽然这无法构成上升子序列,但此时数组的大小,正是由之前10,20,30所扩充的,也保存了最大上升子序列的长度。
程序:
C++
//Dynamic
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size() == ) return ;
int longest = ;
vector<int> res(nums.size(), );
for(int i = ; i < nums.size(); ++i){
for(int j = i; j > ; j--){
if(nums[i] > nums[j-]){
res[i] = max(res[i], res[j-]+);
}
}
}
for(auto n:res){
if(longest < n) longest = n;
}
return longest;
}
};
//Dynamic Programming with Binary Search
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size() == ) return ;
vector<int> res;
res.push_back(nums[]);
for(int i = ; i < nums.size(); ++i){
int index = binarySearch(res, nums[i]);
if(index == -)
res[] = nums[i];
else if(index < -)
res.push_back(nums[i]);
else
res[index] = nums[i];
}
return res.size();
}
int binarySearch(vector<int>& v, int num){
if(num < v[]) return -;
if(num > v[v.size()-]) return -(v.size()+);
int l = ;
int r = v.size()-;
int mid;
while(l <= r){
mid = l + (r-l)/;
if(num < v[mid]) r = mid-;
else if(num > v[mid]) l = mid+;
else return mid;
}
return l;
}
};
Java
//Dynamic Programming with Binary Search
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length == 0) return 0;
int[] res = new int[nums.length];
int size = 0;
for(int i = 0; i < nums.length; ++i){
int index = Arrays.binarySearch(res, 0, size, nums[i]);
if(index < 0) index = -(index+1);
res[index] = nums[i];
if(index == size) size++;
}
return size;
}
}
//Java binarySearch
// [1] 该搜索键在范围内,但不是数组元素,由1开始计数,得“ - 插入点索引值”;
// [2] 该搜索键在范围内,且是数组元素,由0开始计数,得搜索值的索引值;
// [3] 该搜索键不在范围内,且小于范围(数组)内元素,返回–(fromIndex + 1);
// [4] 该搜索键不在范围内,且大于范围(数组)内元素,返回 –(toIndex + 1)。
LeetCode 300. Longest Increasing Subsequence最长上升子序列 (C++/Java)的更多相关文章
- [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最长递增子序列
Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Inp ...
- 300 Longest Increasing Subsequence 最长上升子序列
给出一个无序的整形数组,找到最长上升子序列的长度.例如,给出 [10, 9, 2, 5, 3, 7, 101, 18],最长的上升子序列是 [2, 3, 7, 101],因此它的长度是4.因为可能会有 ...
- 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, ...
- Leetcode 300 Longest Increasing Subsequence
Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...
- leetcode@ [300] Longest Increasing Subsequence (记忆化搜索)
https://leetcode.com/problems/longest-increasing-subsequence/ Given an unsorted array of integers, f ...
- [leetcode] 300. Longest Increasing Subsequence (Medium)
题意: 求最长增长的子序列的长度. 思路: 利用DP存取以i作为最大点的子序列长度. Runtime: 20 ms, faster than 35.21% of C++ online submissi ...
- [LintCode] Longest Increasing Subsequence 最长递增子序列
Given a sequence of integers, find the longest increasing subsequence (LIS). You code should return ...
随机推荐
- idea中applicationContext-dao.xml文件中Cannot resolve file***** :spring xml model validation问题
访问不了classpath下的文件夹中的文件 解决办法如下:(问题出在我创建的resources文件夹是一个普通的文件夹) 1.本来是普通的文件夹 2.ctrl+shift+alt+s打开如下界面: ...
- linux安装python串口工具pyserial遇到不能成功导入的问题
常规方法:pip install pyserial导入serial后提示: 解决方法:apt install python3-serial 参考:https://stackoverflow.com/q ...
- 我真的不想再用 JPA 了
在开发者的圈子里,没当说到一种技术好或者不好,都会引发激烈或者不激烈的争论,直到一个开发者出来说 PHP 是世界上最好的语言,大家伙儿才会纷纷退去继续写代码. 今天说 JPA 的问题不是想引发什么讨论 ...
- FreeSql (三十)读写分离
FreeSql 支持数据库读写分离,本功能是客户端的读写分离行为,数据库服务器该怎么配置仍然那样配置,不受本功能影响,为了方便描术后面讲到的[读写分离]都是指客户端的功能支持. 各种数据库的读写方案不 ...
- 一次写文,多平台直接粘贴&打造最流畅的写作流程
文字爱好者的痛点 这一段可以跳过,解决办法在后面.因为大家既然痛过,也就懂了. 对于很多文字爱好者来说,都希望写一篇文章后,可以实现多平台发布. 国内的很多平台都开始支持 Markdown,除了微信公 ...
- 多线程——Thread类
进程(Process):“正在执行的程序”,程序进入内存运行就变成了一个进程.一个进程会产生多个线程. 多线程(Multithread):一个进程中同时存在几个执行体.单线程是按照函数的顺序执行,多线 ...
- Day 10 用户的提权,用户组的创建删除
1.如何为用户设定密码,又如何修改密码? 2.用户的创建流程? [扩展了解] 3.用户组如何管理? 4.普通用户无权限怎么办? 切换身份 or 提权? su 切换用户 sudo 提权 5.为用户添 ...
- 实践APP安全性检测(一):APK反编译
1.概述 APP安全性一般可以从以下几方面进行考量: 以及其他一些杂项(或者通用并不局限于APP的安全项): 本文讨论反编译问题. 2.APK反编译 安卓开发的APP,如果不做任何处理是很容易被反编译 ...
- 复习0824js
编程思想: 面向过程:凡事亲力亲为,所有事情的过程都要清楚,注重的是过程. 面向对象:提出需求,找到对象,对象解决这个问题,我们要结果,注重的是结果. 面向对象的特性:封装,继承,多态: JS: 是一 ...
- HashMap浅析
一.概述 HashMap,基于哈希结构的Map接口的一个实现,无序,允许null键值对,线程不安全的.可以使用集合工具类Collections中的synchronizedMap方法,去创建一个线程安全 ...