题目:
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?
题意:
给定一个无数的数组,找出最长的递增子序列。
思路:
这道题目是一道典型的题目,算法必练。使用的是动态规划的思路,有两种解法,一个是时间复杂度是O(n^2)的解法,一个是降到O(n*lg(n))的解法。以下分别讨论两种思路。
O(n^2)的 解法:
首先是基本思路,因为考虑的是最长递增子序列,所以我们可以保存第i歌元素之前出现的长度为1的子序列,长度为2的子序列,等等。当考虑当前第i歌元素时我们只需要决定以第i歌元素为结尾的子序列的长度是多大,那么找出前面最长的一个子序列,这个子序列满足的条件是最后一个元素要比当前第i歌元素要小,那么第i歌元素就可以接到这个序列上面从而变长。所以我们保存一个数组来记录,从第1个元素到第i歌元素之间,长度为1,2..i-1的长度的子序列的结尾元素,比如找出第i歌元素只可以接在长度为k的子序列后面,那么接上i之后长度就变成了k+1,那么我们这个时候把k+1长度的子序列的结尾元素变成nums[i]。所以依次扫描nums中的n歌元素时,会顺序遍历一遍各个长度的子序列的结尾,所以最终复杂度是O(n^2)。
接下来考虑O(n*lg(n))的算法:
观察前面的分析我们发现,其实k个长度的子序列的最后一个元素一定是小于k+1个长度的子序列的最后一个元素。所以我们只需要二分查找前面的元素就可以了。
代码如下:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int size = nums.size();
if(size <= 1)return size;
vector<int> increase_sequence;
for(auto i = 0; i < size; i++) {
auto res = lower_bound(increase_sequence.begin(), increase_sequence.end(), nums[i]);
if(res == increase_sequence.end())increase_sequence.push_back(nums[i]);
else increase_sequence[res - increase_sequence.begin()] = nums[i];
}
return increase_sequence.size();
}
};