300. Longest Increasing Subsequence
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(n),其中dp[i]的含义是:nums[0, ..., i]的LIS。它的递推式是:如果nums[i]>nums[j],其中0<=j<i,则dp[i]=max{dp[j]+1}。最终的结果:res=max{dp[0], ... ,dp[n-1]}。
int lengthOfLIS(vector<int>& nums) {
int i, n=nums.size();
if(!n) return 0;
vector<int> dp(n,1);
int res=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<i;j++)
{
if(nums[i]>nums[j])
{
dp[i]=max(dp[i],dp[j]+1);
}
}
res=max(res,dp[i]);
}
return res;
}
算法复杂度: O(n^2)
解法2:点击打开链接 二分搜索
思路:定义一个数组tails(n),其中tails[i]的含义是:LIS长度为i+1的序列的最小的尾部。
例如:对于nums=[4, 5, 6, 3]
len=1: [4], [5], [6], [3] =>tails[0]=3
len=2: [4, 5], [4,6], [5,6] => tails[1]=5
len=3: [4,5,6] =>tails[2]=6
tails数组是递增的。因此我们可以用二分搜索找到,要更新的LIS。
对nums数组中的每个元素遍历时,我们只要做以下两者之一:
1)如果x大于tails的所有元素,那么size++
2)否则,找到这样的tails元素,tails[i-1]<x<=tails[i],更新tails[i]=x。因为len=i的新的LIS,可由tails[i-1]对应LIS后面加x组成。
int lengthOfLIS(vector<int>& nums) {
int i, n=nums.size();
if(!n) return 0;
vector<int> tails(n);
int size=0;
for(int num:nums)
{
int i=0,j=size;
while(i<j)
{
int m=(i+j)/2;
if(tails[m]<num)
i=m+1;
else j=m;
}
tails[i]=num;
if(i==size) size++;
}
return size;
}
时间复杂度:O(nlgn)
仍然是解法2,有更简单的代码写法。来源于此
<span style="font-size:18px;"> int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
if(!n) return 0;
vector<int> tails;
for(int num:nums)
{
auto it=lower_bound(tails.begin(),tails.end(),num);
if(it==tails.end()) tails.push_back(num);
else *it=num;
}
return tails.size();
}</span>
说明:auto it=lower_bound(tails.begin(),tails.end(),num);
lower_bound返回一个迭代器,该迭代器指向第一个不小于num的元素。如果指向结尾,说明当前元素大于tails里的所有元素,直接加入,否则,将第一个不小于num的元素*it,更新为num.