300. 最长递增子序列

题目链接:300. 最长递增子序列

方法:动态规划

解题思路

  • 状态表示:\(dp[]\)
    • 集合:表示以 \(i\) 结尾的所有递增子序列;
    • 属性:\(dp[i]\) 表示集合中最长子序列的长度。
  • 状态计算:
    • 集合划分:枚举以 \(i\) 结尾的所有递增子序列的其前一个元素可能的下标 [0, i - 1],将其划分为以 \(i\) 结尾的所有递增子序列中前一个元素是 \(j\)的集合,\(0 <= j <= i - 1, nums[j] < nums[i]\)
    • \(dp[i] = max\{dp[j] + 1, 1\}\)

代码

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        int dp[n]; memset(dp, 0, sizeof(dp));
        dp[0] = 1;
        int ans = 1;
        for (int i = 1; i < n; i ++ ) {
            dp[i] = 1;
            for (int j = 0; j < i; j ++ ) {
                if (nums[i] > nums[j]) {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};

优化解法:单调 + 二分

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        int ans = 0, q[n + 1]; memset(q, 0, sizeof(q));
        q[0] = -2e9;
        for (int i = 0; i < n; i ++ ) {
            int l = 0, r = ans;
            while (l < r) {
                int mid = l + r + 1 >> 1;
                if (q[mid] < nums[i]) l = mid;
                else r = mid - 1;
            }
            ans = max(ans, r + 1);
            q[r + 1] = nums[i];
        }
        return ans;
    }
};
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        int ans = 0, q[n + 1]; memset(q, 0, sizeof(q));
        q[0] = -2e9;
        for (int i = 0; i < n; i ++ ) {
            int idx = lower_bound(q, q + ans + 1, nums[i]) - q;
            ans = max(ans, idx);
            q[idx] = nums[i];
        }
        return ans;
    }
};

复杂度分析

时间复杂度:\(dp\)\(O(n^2)\),优化—\(O(nlogn)\)
空间复杂度:\(O(n)\)

posted @ 2023-04-11 22:04  lixycc  阅读(23)  评论(0)    收藏  举报