Given an unsorted array of integers, find the length of longest increasing subsequence.

For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that 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?

思路:DP。这题有两种解法。

首先,是经典的O(N^2)解法。

我们维护一个一维数组,dp[i]表示以nums[i]为最后一位的最长递增子序列的长度。

递推公式为dp[i] = max(dp[j] + 1) 其中 0 <= j < i 且 nums[j] < nums[i]。

 class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
if (n < ) return n;
vector<int> dp(n, );
int res = INT_MIN;
for (int i = ; i < n; i++)
for (int j = ; j < i; j++)
if (nums[j] < nums[i])
dp[i] = max(dp[i], dp[j] + );
for (int i = ; i < n; i++)
res = max(res, dp[i]);
return res;
}
};

下面介绍O(NlogN)的算法。

该算法的主要思想可以用一个例子来说明。如果有两个数nums[a],nums[b],且nums[a] < nums[b],而dp[a] = dp[b],即以这两个数截止的最长递增子序列的长度是相等的,那么如果后面还有数,很明显我们要优先选择nums[a],因为它更小,选它则之后获得更长增长子序列的机会更大。

因此这里我们用len来记录目前已经发现的最长增长子序列的长度。

用一个int数组MinLastNumOfLenOf[k]来表示目前已经发现的,长度为k的最长增长子序列的最后一个元素的最小值。这里数组名字起这么长纯粹是为了好理解。

那么会发现MinLastNumOfLenOf中的值是递增的,即对于i < j有M[i] < M[j]。否则,假设M[j] < M[i] 且j > i,那么我们按照定义完全可以让M[i] 等于M[j]的值,这样会更优。同时,M[i]的值在算法运行过程中只降不增。

在实际进行中,len为当前我们已经发现的最长增长子序列的长度,而MinLastNumOfLenOf[len]则记录了该最长子序列的最后一个元素(最小的)。

当我们进行到nums[i]时,如果nums[i] > MinLastNumOfLenOf[len],则明显我们获得了一个更长的增长子序列,因此将len加一,然后令MinLastNumOfLenOf[len] = nums[i]。

否则,如果nums[i] < MinLastNumOfLenOf[len],则我们可以找到一个最小的下标k,k满足MinLastNumOfLenOf[k] > nums[i],然后我们将MinLastNumOfLenOf[k]更新为nums[i]的值。这里,因为M数组的值是递增的,我们可以用二分查找来找到这个下标,复杂度为O(logn)。

可能你会有疑问,我们都已经发现了长度为len的子序列了,为什么还要更新前面MinLastNumOfLenOf[k]的值呢?因为实际上M[1]...M[len]串连起来就是我们的最长增长子序列。但是,如果我们将后续的一个数nums[i] < M[len]更新到M数组中,假设更新到了M[k],则明显,M[1]...M[k]仍然是一个最长增长子序列,而M[1]...到M[k+1]以及后面的元素就不是了,因为我们新插入的这个数是后加进来的,也就是说在nums[i]中的下标i是要大于M[k+1]...M[len]这些数在nums中的下标的。每次我们更新M数组时总会有这个规律,而且,当我们将M[k]更新得更小后,则M[k+1]被更新的机会就更大,毕竟M[k]不可能无限小下去。而且,虽然M[k]更新后,M[1]...M[len]就无法构成一个合法的增长子序列,但我们已经用len保存了当前所发现的最长值,因此并无大碍。以上过程一直持续到我们找到一个新的数,而它仅小于M[len]时,M[len]被更新了,此时我们终于找到了一个长度为len且最后一个元素更小的子序列,而这使得后续找到更长的子序列的机会更大了!

 class Solution {
public:
int findInd(vector<int>& d, int num)
{
int left = , right = d.size() - ;
while (left < right)
{
int mid = (left + right) >> ;
if (d[mid] < num) left = mid + ;
else if (mid != && d[mid - ] < num)
return mid;
else right = mid;
}
return left;
}
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
if (n < ) return n;
int len = ;
vector<int> MinLastNumOfLenOf(, );
MinLastNumOfLenOf[len] = nums[];
for (int i = ; i < n; i++)
{
if (nums[i] > MinLastNumOfLenOf[len])
{
MinLastNumOfLenOf.push_back(nums[i]);
len++;
}
else if (nums[i] < MinLastNumOfLenOf[len])
MinLastNumOfLenOf[findInd(MinLastNumOfLenOf, nums[i])] = nums[i];
}
return len;
}
};

Longest Increasing Subsequence - LeetCode的更多相关文章

  1. [LeetCode] Longest Increasing Subsequence 最长递增子序列

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

  2. leetcode@ [300] Longest Increasing Subsequence (记忆化搜索)

    https://leetcode.com/problems/longest-increasing-subsequence/ Given an unsorted array of integers, f ...

  3. [LeetCode] Number of Longest Increasing Subsequence 最长递增序列的个数

    Given an unsorted array of integers, find the number of longest increasing subsequence. Example 1: I ...

  4. LeetCode Number of Longest Increasing Subsequence

    原题链接在这里:https://leetcode.com/problems/number-of-longest-increasing-subsequence/description/ 题目: Give ...

  5. [LeetCode] 300. Longest Increasing Subsequence 最长递增子序列

    Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Inp ...

  6. [LeetCode] 673. Number of Longest Increasing Subsequence 最长递增序列的个数

    Given an unsorted array of integers, find the number of longest increasing subsequence. Example 1: I ...

  7. 【LeetCode】673. Number of Longest Increasing Subsequence 解题报告(Python)

    [LeetCode]673. Number of Longest Increasing Subsequence 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https:/ ...

  8. 【LeetCode】300. Longest Increasing Subsequence 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  9. Leetcode 300 Longest Increasing Subsequence

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

随机推荐

  1. SQL中的函数用法

    一.coalesce COALESCE (expression_1, expression_2, ...,expression_n)依次参考各参数表达式,遇到非null值即停止并返回该值.如果所有的表 ...

  2. 第三模块 面向对象& 网络编程基础 实战考核

    1.简述构造方法和析构方法. 构造方法(__init__):主要作用是实例化时给实例一些初始化参数,或执行一些其它的初始化工作,总之因为这个__init__只要一实例化, 就会自动执行,不管你在这个方 ...

  3. 通过js date对象获取各种开始结束日期的示例

    有时候做一些任务计划的功能时候,需要提供一个开始时间或者结束时间,比如本周结束,本月结束,今天结束等等,因此,我参考网上的资料把相关的实现为一个项目: gitee: https://gitee.com ...

  4. flex遭遇text-overflow:hidden,white-space:nowrap

    最近在项目中遇到使用flex的时候,在flex-item元素中使用text-overflow:hidden:white-space:nowrap:进行省略文字的操作. 发现flex-item失控了,长 ...

  5. 踩坑 Uncaught RangeError: Maximum call stack size exceeded

    今天遇到了一个错误, 堆栈溢出,很好奇就是一个简单ajax请求怎么会报这个错误,研究了一下,发现犯了一个很低级的错误,data的参数错误了: passWord是未定义的变量,值为空,然后导致了这个问题 ...

  6. C#中var、int、object性能比较(已修正)

    var关键字是.net3.5推出的关键字,主要是让编译器自动推断并判断变量类型,类似javascript中的var. 在使用一些性能优化软件时,在代码优化时,我发现不管定义什么类型的变量,变量的类型都 ...

  7. 【转】unity自带寻路Navmesh入门教程(一)

    http://liweizhaolili.blog.163.com/blog/static/16230744201271161310135/ 说明:从今天开始,我阿赵打算写一些简单的教程,方便自己日后 ...

  8. line-height与vertical-align

    css世界读书笔记: 内联元素与流 块级元素负责结构,内联元素接管内容 x元素的下边缘就是我们的基线baseline x-height就是x的高度 vertical-align:middle是x中点位 ...

  9. CMake 使用笔记

    记录 CMake 相关知识. Prelude:读文档一定要有耐心! 问题一 CLion: CMakeLists.txt 中 set(CMAKE_CXX_FLAGS -Wall) 不起作用 Soluti ...

  10. cf 843 A Sorting by Subsequences [建图]

    题面: 传送门 思路: 这道题乍一看有点难 但是实际上研究一番以后会发现,对于每一个位置只会有一个数要去那里,还有一个数要离开 那么只要把每个数和他将要去的那个位置连起来,构成了一个每个点只有一个入边 ...