leetcode[300] Longest Increasing Subsequence

題目:給定一個無序的整數數組,找到其中最長上升子序列的長度。

輸入:整數數組

輸出:最長上升子序列的長度

思路:動態規劃

爲了探究從較短的上升子序列到較長的上升子序列的關係,我們關注較短的上升子序列的結尾,因此,定義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)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章