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(n2)的方法:
借助一个辅助的数组hash[],hash中记录了以当前元素为最后一个元素的最长序列的值。
遍历给的数组nums[],每次遍历都向左找一个比他小的数,当前的最长序列就是比他小的数的hash值+1。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int maxLen = 0;
vector<int> hash(nums.size()+1, 1);
for(int i = 0; i< nums.size(); i++)
{
int j = i -1;
while(j >= 0)
{
if(nums[i] > nums[j])
hash[i] = max(hash[j]+1, hash[i]);
j--;
}
maxLen = hash[i]>maxLen?hash[i]:maxLen;
}
return maxLen;
}
};
O(nlogn)解法:
这个解法应该是改自耐心排序。同样借助一个辅助数组sub,这个数组里记录了最长的递增子序列,尽可能保证这里面的元素最小。从头遍历nums,先把nums中第一个元素放到sub中,然后开始遍历数组。如果sub中最后一个元素小于第i个元素,说明sub中有元素应该更新,用折半查找找到第一个比第i个元素小的,替换掉。如果大,那么直接加入到sub的尾部。最后返回sub的长度即可。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int *sub = new int[nums.size()];
int length = 0;
for(int i = 0;i<nums.size();i++)
{
if(i == 0)
{
sub[length++] = nums[i];
}
else
{
if(sub[length-1] < nums.at(i))//直接插入在最后
{
sub[length++] = nums.at(i);
}
else if(sub[length-1] > nums.at(i))//折半插入
{
insert(sub, length, nums.at(i));
}
}
}
return length;
}
void insert(int *sub, int &length, int &value)
{
int l = 0;
int h = length - 1;
while(l<=h)
{
int mid = (l+h)/2;
if(value > sub[mid]) l = mid+1;
else h = mid -1;
}
sub[l] = value;
}
};
参考:
这里写链接内容