題目:給定一個無序的整數數組,找到其中最長上升子序列的長度。
輸入:整數數組
輸出:最長上升子序列的長度
思路:動態規劃
爲了探究從較短的上升子序列到較長的上升子序列的關係,我們關注較短的上升子序列的結尾,因此,定義dp[i]爲以num[i]爲結尾的最長上升子序列的長度。
遞推關係式:
代碼:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int size=nums.size();
if(size==0)
return 0;
vector<int> dp(size, 1); // dp[i]: max_length(end as nums[i])
for(int i=0;i<size;++i)
{
for(int j=0;j<i;++j)
{
if(nums[j]<nums[i])
{
dp[i]=max(dp[j]+1,dp[i]);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};
複雜度分析:時間複雜度O(n^2),空間複雜度O(n)。
思路2:二分+DP
修改狀態定義,tail[i]表示長度爲i+1的所有上升子序列的結尾的最小值。
狀態轉移過程:
第一步,比較當前遍歷的數num和tail最後一個數,如果num>tail最後一個數,則將num加在tail最後,跳至第三步。
第二步,在tail中找到第一個大於等於num的數,用num將其替換掉。
第三步,遍歷下一個數num。
由於tail是嚴格有序數組,因此可以用二分查找加快程序。
代碼:
class Solution{
public:
int lengthOfLIS(vector<int>& nums){
int len=nums.size();
if(len==0)
return 0;
vector<int> tail;
tail.push_back(nums[0]);
int end=0;
for(int i=1;i<len;++i)
{
if(nums[i]>tail[end])
{
tail.push_back(nums[i]);
end++;
}
else
{
int left=0;
int right=end;
while(left<right)
{
int mid=(left+right)>>1;
if(nums[i]<=tail[mid])
right=mid;
else
left=mid+1;
}
tail[right]=nums[i];
}
}
return end+1;
}
};
複雜度分析:時間複雜度O(nlogn),空間複雜度O(n)。