LeetCode 300.最长递增子序列|通俗易懂的DP解法拆解

0 阅读2分钟

最长递增子序列(LIS)是算法面试高频基础题,也是动态规划入门的经典题型。很多人容易混淆子序列和子数组,子序列不要求连续、仅保留元素相对顺序,这也是本题的核心考点。

image.png

对于本题,在数据范围长度≤2500的前提下,O(n²)的动态规划解法是足够的

核心解题思路

解题关键是反向递推:不全局找最长序列,而是逐个确定「以当前元素结尾的最长递增子序列长度」。

我们定义 dp[i] :以数组第 i 个元素结尾的最长严格递增子序列长度。 初始状态很简单:每个元素自身就是一个长度为1的子序列,所以 dp 数组全部初始化为1。

状态转移逻辑清晰易懂:遍历每个元素 nums[i] ,再回头对比它之前的所有元素 nums[j] 。如果 nums[i] > nums[j] ,说明当前元素可以接在 nums[j] 的递增子序列后,此时更新 dp[i] = Math.max(dp[i], dp[j] + 1) 。

全程遍历结束后, dp 数组中的最大值,就是整个数组的最长递增子序列长度。

JavaScript 简洁代码

var lengthOfLIS = function(nums) {
    const n = nums.length;
    let dp = new Array(n).fill(1);
    let maxLen = 1;
    for(let i = 1;< n; i++){
        for(let j = 0; j < i; j++){
            if(nums[i] > nums[j]){
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
        maxLen = Math.max(maxLen, dp[i]);
    }
    return maxLen;
};

复杂度与刷题总结

时间复杂度:O(n²),双重循环遍历数组,适配题目数据范围。 空间复杂度:O(n),额外开辟dp数组存储状态。

这套解法没有复杂逻辑,核心就是拆分最优子结构,把全局难题拆解为每个位置的局部最优解