最长递增子序列 (Longest Increasing Subsequence)

在一个随机序列中,寻找最长的递增子序列,这个子序列不要求连续。比如,给定序列[10, 9, 2, 5, 3, 7, 19, 18], 最长子序列为[2,3,7,19]或者[2,3,7,18], 因此结果为4。

第一种解法,是采用动态规划,复杂度为O^2. 使用一个辅助数组dp, 其中dp[i]保存源数组中以下标i结尾的最长递增子序列的个数.

n[0] = 10, dp[0] = 1  
n[1] = 9  , dp[1] = 1
n[2] = 2  , dp[2] = 1
n[3] = 5  , dp[3] = 2  (2, 5)
n[4] = 3  , dp[4] = 2  (2, 3)
n[5] = 7  , dp[5] = 3  (2, 3, 7)
n[6] = 19, dp[6] = 4 (2, 3, 7, 19)
n[7] = 18, dp[7] = 4 (2, 3, 7, 18)

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.empty()) return 0;

        int ans = 1;
        vector<int> dp(nums.size(),1);
        for(int i = 1; i < nums.size(); i++) {
            int maxC = 1;
            for(int j = i-1; j >= 0; j--) {
                if(nums[i] > nums[j]) {
                    maxC = max(maxC,dp[j]+1);
                }
            }
            dp[i] = maxC;
            ans = max(ans, maxC);
        }
        return ans;
    }
};

第二种解法则用dp[i]保存长度为i+1的递增子序列中的最后一个元素。因为可能有多个长度为i+1的子序列,dp[i]保存最小的一个元素, 复杂度为n*log(n).

n[0] = 10, dp = [10]
n[1] = 9  , dp = [9]
n[2] = 2  , dp = [2]
n[3] = 5  , dp = [2,5]
n[4] = 3  , dp = [2,3]
n[5] = 7  , dp = [2,3,7]
n[6] = 19, dp = [2,3,7,19]
n[7] = 18, dp = [2,3,7,18]

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.empty()) return 0;
        
        vector<int> dp;
        for(int i = 0; i < nums.size(); i++) {
            if(dp.empty() || nums[i] > dp.back()) {
                dp.push_back(nums[i]);
            }
            else {
                auto it = lower_bound(dp.begin(), dp.end(), nums[i]);
                *it = nums[i];
            }
        }
        return dp.size();
    }
};

点赞