力扣HOT100(52)动态规划 - 最长递增子序列

先搞懂:什么是「子序列」?

这是新手最容易搞混的点,一定要和「子串」区分开:

  • 子串 :必须是数组中连续的一段元素
  • 子序列 :可以不连续,但元素的相对顺序不能变

比如数组 [10,9,2,5,3,7,101,18]

  • 子串:[2,5,3](连续)
  • 子序列:[2,3,18](不连续,但顺序不变)

题目要求

找到数组中最长的严格递增子序列的长度

  • 严格递增:后一个元素必须大于前一个,不能等于
  • 子序列可以不连续,但顺序不能乱

核心思路(一句话讲透)

dp[i] 表示:以第 i 个元素结尾的最长递增子序列的长度 。 对于每个元素 nums[i],我们看它前面所有比它小的元素 nums[j](j < i):

  • 如果 nums[j] < nums[i],说明 nums[i] 可以接在 nums[j] 后面,形成一个更长的子序列
  • 这个更长的子序列长度就是 dp[j] + 1
  • 我们在所有可能的 dp[j] + 1 中取最大值,就是 dp[i] 的值

所以状态转移方程:

plaintext

复制代码
dp[i] = max(dp[j] + 1)  (其中 0 ≤ j < i 且 nums[j] < nums[i])

完整解题步骤

  1. 处理边界情况:如果数组为空,直接返回 0
  2. 初始化 dp 数组
    • 数组长度为 n(和原数组一样长)
    • 所有元素初始化为1(因为每个元素自己就是一个长度为 1 的子序列)
  3. 遍历计算 dp 数组
    • 外层循环:i0n-1(当前要计算的元素)
    • 内层循环:j0i-1(前面所有的元素)
      • 如果 nums[j] < nums[i](可以接在后面)
      • 更新 dp[i] = max(dp[i], dp[j] + 1)
  4. 返回结果 :dp 数组中的最大值
    • 注意:最长子序列不一定以最后一个元素结尾,所以不能直接返回dp[n-1]
cpp 复制代码
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if(n == 0)
            return 0;


        vector<int> dp(n,1);//初始值设成1 因为序列最短包括自己 长度为1

        for(int i = 0;i<n;i++){
            for(int j = 0;j<i;j++){
                if(nums[j]<nums[i]){
                    dp[i] = max(dp[i],dp[j]+1);
                }
            }
        }  

        return *max_element(dp.begin(),dp.end());
    }
};
相关推荐
To_OC6 小时前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
用户9385156350711 小时前
从 O(n²) 到 O(nlogn):一文读懂快速排序的“快”与“妙”
javascript·算法
To_OC12 小时前
手写快排次次翻车?别死背快排模板了,这才是面试官想听的底层逻辑
javascript·算法·排序算法
饼干哥哥13 小时前
Reddit VOC调研太慢?搭一个AI专家团队半小时洞察任何品类|以猫用饮水机为例
人工智能·算法·ai编程
地平线开发者14 小时前
Transformer模型部署之性能优化指南
算法
地平线开发者14 小时前
人在途中:从“编译失败”到“模型可落地”——CUDA 自定义算子
算法·自动驾驶
半个落月17 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
小月土星18 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星18 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试